NodeJS实现微信公众号关注后自动回复功能
程序员文章站
2022-06-20 16:26:15
一 实先自动回复功能的逻辑步骤
1 处理post类型的控制逻辑,接收xml的数据包;
2 解析xml数据包(获得数据包的消息类型或者是事件类型);
3 拼...
一 实先自动回复功能的逻辑步骤
1 处理post类型的控制逻辑,接收xml的数据包;
2 解析xml数据包(获得数据包的消息类型或者是事件类型);
3 拼装我们定义好的消息;
4 包装成xml格式;
5 在5秒内返回回去
二 代码实操
本节代码参照上节课继续修改和完善,目录结构跟之前相同,新引入的模块raw-body使用npm install安装一下即可,app.js启动文件和util.js不做变动,主要修改一下generator.js文件,以及在generator.js同级目录下新建wechat.js文件和tools.js文件。
wechat.js文件是将前一节generator.js文件中票据部分的代码抽离出来单独放在一个文件中,具体代码如下:
'use strict'; // 引入模块 var promise = require('bluebird'); var request = promise.promisify(require('request')); //增加url配置项 var prefix = 'https://api.weixin.qq.com/cgi-bin/'; var api = { accesstoken: prefix + 'token?grant_type=client_credential' }; //利用构造函数生成实例 完成票据存储逻辑 function wechat(opts) { var that = this; this.appid = opts.appid; this.appsecret = opts.appsecret; this.getaccesstoken = opts.getaccesstoken; this.saveaccesstoken = opts.saveaccesstoken; //获取票据的方法 this.getaccesstoken() .then(function(data) { //从静态文件获取票据,json化数据,如果有异常,则尝试更新票据 try { data = json.parse(data); } catch (e) { return that.updateaccesstoken(); } //判断票据是否在有效期内,如果合法,向下传递票据,如果不合法,更新票据 if (that.isvalidaccesstoken(data)) { promise.resolve(data); } else { return that.updateaccesstoken(); } }) //将拿到的票据信息和有效期信息存储起来 .then(function(data) { //console.log(data); that.access_token = data.access_token; that.expires_in = data.expires_in; that.saveaccesstoken(data); }) }; //在wechat的原型链上增加验证有效期的方法 wechat.prototype.isvalidaccesstoken = function(data) { //进行判断,如果票据不合法,返回false if (!data || !data.access_token || !data.expires_in) { return false; } //拿到票据和过期时间的数据 var access_token = data.access_token; var expires_in = data.expires_in; //获取当前时间 var now = (new date().gettime()); //如果当前时间小于票据过期时间,返回true,否则返回false if (now < expires_in) { return true; } else { return false; }; }; //在wechat的原型链上增加更新票据的方法 wechat.prototype.updateaccesstoken = function() { var appid = this.appid; var appsecret = this.appsecret; var url = api.accesstoken + '&appid=' + appid + '&secret=' + appsecret; return new promise(function(resolve, reject) { //使用request发起请求 request({ url: url, json: true }).then(function(response) { var data = response.body; var now = (new date().gettime()); var expires_in = now + (data.expires_in - 20) * 1000; //把新票据的有效时间赋值给data data.expires_in = expires_in; resolve(data); }) }) }; //向外暴露wechat module.exports = wechat;
generator.js文件进行精简后,添加判断对xml数据的格式化方法以及判断事件,添加关注事件测试信息,具体代码如下:
'use strict'; // 引入模块 var sha1 = require('sha1'); var getrawbody = require('raw-body'); var wechat = require('./wechat'); var tools = require('./tools'); // 建立中间件函数并暴露出去 module.exports = function(opts) { //实例化wechat()函数 //var wechat = new wechat(opts); return function*(next) { //console.log(this.query); var that = this; var token = opts.token; var signature = this.query.signature; var nonce = this.query.nonce; var timestamp = this.query.timestamp; var echostr = this.query.echostr; // 进行字典排序 var str = [token, timestamp, nonce].sort().join(''); // 进行加密 var sha = sha1(str); //使用this.method对请求方法进行判断 if (this.method === 'get') { // 如果是get请求 判断加密后的值是否等于签名值 if (sha === signature) { this.body = echostr + ''; } else { this.body = 'wrong'; }; } else if (this.method === 'post') { //如果是post请求 也是先判断签名是否合法 如果不合法 直接返回wrong if (sha !== signature) { this.body = 'wrong'; return false; }; //通过raw-body模块 可以把把this上的request对象 也就是http模块中的request对象 去拼装它的数据 最终拿到一个buffer的xml数据 //通过yield关键字 获取到post过来的原始的xml数据 var data = yield getrawbody(this.req, { length: this.length, limit: '1mb', encoding: this.charset }); //console.log(data.tostring());打印xml数据(当微信公众号有操作的时候 终端可以看到返回的xml数据) //tools为处理xml数据的工具包 使用tools工具包的parsexmlasync方法 把xml数据转化成数组对象 var content = yield tools.parsexmlasync(data); //console.log(content);打印转化后的数组对象 //格式化content数据为json对象 var message = tools.formatmessage(content.xml); console.log(message); //打印message //判断message的msgtype 如果是event 则是一个事件 if (message.msgtype === 'event') { //如果是订阅事件 if (message.event === 'subscribe') { //获取当前时间戳 var now = new date().gettime(); //设置回复状态是200 that.status = 200; //设置回复的类型是xml格式 that.type = 'application/xml'; //设置回复的主体 that.body = '<xml>' + '<tousername><![cdata[' + message.fromusername + ']]></tousername>' + '<fromusername><![cdata[' + message.tousername + ']]></fromusername>' + '<createtime>' + now + '</createtime>' + '<msgtype><![cdata[text]]></msgtype>' + '<content><![cdata[你好,同学!]]></content>' + '</xml>'; return; } } } } };
tools.js是处理xml数据的工具文件:
'use strict'; //引入模块 var xml2js = require('xml2js'); var promise = require('bluebird'); //导出解析xml的方法 exports.parsexmlasync = function(xml) { return new promise(function(resolve, reject) { xml2js.parsestring(xml, { trim: true }, function(err, content) { if (err) { reject(err); } else { resolve(content); }; }); }); }; //因为value值可能是嵌套多层的 所以先对value值进行遍历 function formatmessage(result) { //声明空对象message var message = {}; //对result类型进行判断 if (typeof result === 'object') { //如果是object类型 通过object.keys()方法拿到result所有的key 并存入keys变量中 var keys = object.keys(result); //对keys进行循环遍历 for (var i = 0; i < keys.length; i++) { //拿到每个key对应的value值 var item = result[keys[i]]; //拿到key var key = keys[i]; //判断item是否为数组或者长度是否为0 if (!(item instanceof array) || item.length === 0) { //如果item不是数组或者长度为0 则跳过继续向下解析 continue; } //如果长度为1 if (item.length === 1) { //拿到value值存入val变量 var val = item[0]; //判断val是否为对象 if (typeof val === 'object') { //如果val为对象 则进一步进行遍历 message[key] = formatmessage(val); } else { //如果不是对象 就把值赋给当前的key放入message里 并去除收尾空格 message[key] = (val || '').trim(); } } //如果item的长度既不是0也不是1 则说明它是一个数组 else { //把message的key设置为空数组 message[key] = []; //对数组进行遍历 for (var j = 0, k = item.length; j < k; j++) { message[key].push(formatmessage(item[j])); } } } } return message; } exports.formatmessage = function(xml) { return new promise(function(resolve, reject) { xml2js.parsestring(xml, { trim: true }, function(err, content) { if (err) { reject(err); } else { resolve(content); }; }); }); }; exports.formatmessage = formatmessage;
完成这节的代码后,当关注微信测试公众号的时候,会自动回复『你好,同学!』的提示信息。
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持。
上一篇: 吃什么食物可以减肥 四种减肥食物推荐
下一篇: 红蕨菜能吃吗,一起来看看