Part 1. 验证公众号 (开发者)
- 名词解释
- timestamp 时间戳
- nonce 随机数
- token+timestamp+nonce
- signature 签名
- 验证顺序
- 上面三者排序
- 拼接后利用sha1模块进行加密
- 与signature进行对比
相等就表示来源于微信,返回echostr
Part 2. acess_token获取与储存
- 当普通微信用户向公众账号发消息时,微信服务器将POST消息的XML数据包到开发者填写的URL上。
- 名词解释
- acess_token :凭据,有效期2h,没两个小时就要重新获取(获取完上一个失效)一种凭证,而且要保证他只在唯一位置,不然会发生冲突官方解释
- 设计思路
- 创建构造函数,有请求方的appID、appSecret属性以及对acess_token进行操作的两个方法getAccessToken、saveAccessToken
- 在其原型上还定义了两个方法isVaildAccessToken、updateAccessToken,分别用来识别凭证的有效性、若失效或者没有凭证则重新发送请求进行acess_token更新
- 创建了一个txt文件来储存acess_token(使用了fs模块:读取写入文件),文件写入和读取功能可以单独储存在一个公共方法util.js中,配置文档路径(path模块)
Part 3. 回复测试
- 流程
- 接收请求以及对请求信息的处理
接收的请求使用getRawBody模块来进行处理,可以拼装成一个bufferde的xml数据,其参数是请求对象,对应也就是ctx.req。
因为获取的是一个xml数据,要对xml转化成js,使用了xml2js模块,然后获取的xml对象中是数组形式,要重新遍历,将其元素剖析出来,所以编写了一个formatMessage的方法,分别判断属性值是否存在或类型是否为对象,然后遍历到新的对象,这个方法有点像写原生对象深复制,最后返回一个完整的对象数据message。
- 返回数据到用户
- 判断请求方法是'GET'还是'POST',当请求方法也就是message.MsgType为‘GET’,我们可以通过判断message.Event类型,来响应用户端的具体操作
- e.g(subscribe订阅事件) 当message.Event 为 'subscribe' 是用户进行了订阅操作,我们通过书写响应体来进行该请求的响应,返回的数据类型是ctx.type = 'application/xml',以及返回成功状态 ctx.status = 200,还有响应的内容要依据官方给定文档格式返回,ctx.body = 官方特定格式
- e.g(返回文本消息)其格式为
ctx.body = '<xml>' +
'<ToUserName><![CDATA[' + message.FromUserName + ']]></ToUserName>' +
'<FromUserName><![CDATA[' + message.ToUserName +']]></FromUserName>' +
'<CreateTime>' + now + '</CreateTime>' +
'<MsgType><![CDATA[text]]></MsgType>' +
'<Content><![CDATA[欢迎关注Chan的微信公众号]]></Content>' +
'</xml>'
// FromUserName 接收方
// ToUserName 发送方
// CreateTime 时间戳
// MsgType 消息类型
// Content 消息数据
Part 4. 消息处理
- 模板书写
模板书写的是返回格式,返回的格式是微信定好的,可以在官方文档中查询,主要区别是在回复类型的不同,回复的格式也不同。通过变量msgType(返回数据类型)来编译模板进行输出,因为返回的是字符串拼接,所以使用了heredoc模块(书写)以及ejs模块(编译)来对应数据类型的输出 - 定制业务回复数据
回复格式的模板写好了,我们可以定义回复内容,并返回回复内容等待下一步输出,依据回复格式,回复文本则只需要设置content变量,而视频或文章等需要定义多个变量,所以创建一个新的模块来定制回复内容的业务处理。- 因为使用koa所以该步骤通过await调用并获取微信服务器返回并处理过的message数据。依据用户提供的信息设置回复内容content,最终返回需要回复的content,并调用next,执行下一步代码
- 此时app已经获得了content,需要通过第一步制作的模板编译后保存到ctx.body,然后设置status, type。对微信服务器发送请求,等待服务器对用户进行信息回复。
Part 5. 微信SDK应用
- 配置
- 绑定域名 (备案,一级以上)
- 引入JS文件 (直接添加一个html页面到一个中间件中:可以不用路由 )
- JS SDK的初始化 -- 使得内置网页可以调用微信原生应用(扫一扫,摇一摇,拍照,语音等)
依赖
koa 框架 类似express框架 --回调中间件应用
sha1 --加密模块
request --请求封装模块 --请求使用
bluebird --node上的实现Pormise的模块,而且还可以让request模块promisify化
raw-body --解析请求还能限制其数据内容或格式
xml2js --将xml数据格式转化成js对象
heredoc --创建多行字符串
ejs --可以在编译模板中使用了<% %>的代码,使得在字符创中可以直接使用JS代码
ES6知识须知
- generator 生成器(可以使得函数在哪一步进行暂停或继续执行等) generator,配合yield方法来确定回调顺序
- Promise ----> 使得回调更好的维护,更清晰,将回调的函数单独抽离出来分别用
.then(成功执行)
.catch(错误执行)
node blurbird模块实现了原生promise的方法
new Promise((resolve, reject) => {}) // 使用方法
成功使用resolve返回,失败使用reject返回
问题
- koa运行时警告
koa deprecated Support for generators will be removed in v3
使用新的写法即可,参考
https://github.com/koajs/koa/
注意使用了koa2以上的版本后响应和请求对象不再this,而是在一开始设置的ctx参数中了。之前一般this获取的方法或属性获取不到注意下是不是ctx有关。 - request发送请求后返回的data在响应对象responce的body属性中
.then(res=>{console.log(res.body)}) ===>request promisify化 - 当和微信公众号平台进行连接时,提示了token check fail 但是返回的数据又相等,可能是域名填写的问题(我是用的是云服务器给的公网IP解析了一个域名,域名没备案不让使用,所以能接受但用不了,可以直接用IP连接)
- Koa中间件的数据传递,可以将数据储存在ctx.state,亦或是使用call方法将执行上下文改为ctx,来获取数据。
// app.js
ctx.state.msg = message // 把解析好的message储存 koa的特有方法就是存在state中
await handler(ctx, next) // 让业务处理储存好的message
// handler.js
var message = ctx.state.msg // 来获取储存的数据
reply.call(ctx) // 处理完后调用回复的方法
// reply.js
var body = this.body // this.body ,因为绑定了ctx ===> 和在app中调用 ctx.body一样
- 在上传临时素材并设置公众号返回信息时,若文件比较大上传时间长,微信服务器等待响应超过5s则不会返回视频,并且会重复3次请求,这样就进行了3次上传,一般情况下不建议自动回复临时上传的视频,而是直接调用上传后的素材后微信服务器返回的media_id
- 有时候会提示.then 未定义,是因为前面的代码有的没有返回Promise对象,多以导致使用不了then的方法。
- 有关相机相册、地理位置的信息事件信息,微信服务器会先返回一个当前事件的事件信息,然后在返回一个普通消息(照片对应回复照片信息,地理位置对应地理位置)扫描二维码只返回一个事件消息。
- koa中中间件传递POST数据时记得next(ctx),要将ctx传递下去否则会发生FORM数据错误