引荐4款微信小程序_NodeJS完成微信大众号重视后主

2021-01-12 10:55

NodeJS实现微信公众号关注后自动回复功能       这篇文章主要为大家详细介绍了NodeJS实现微信公众号关注后自动回复功能,具有一定的参考价值,感兴趣的小伙伴们可以参考一下

一 实先自动回复功能的逻辑步骤

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 = '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;
 essToken = essToken;
 essToken = essToken;
 //获取票据的方法
 essToken()
 .then(function(data) {
 //从静态文件获取票据,JSON化数据,如果有异常,则尝试更新票据
 try {
 data = JSON.parse(data);
 } catch (e) {
 return essToken();
 //判断票据是否在有效期内,如果合法,向下传递票据,如果不合法,更新票据
 if (essToken(data)) {
 Promise.resolve(data);
 } else {
 return essToken();
 //将拿到的票据信息和有效期信息存储起来
 .then(function(data) {
 //console.log(data);
 that.access_token = data.access_token;
 that.expires_in = data.expires_in;
 essToken(data);
//在weChat的原型链上增加验证有效期的方法
weChat.essToken = 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.essToken = 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 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;

完成这节的代码后,当关注微信测试公众号的时候,会自动回复『你好,同学!』的提示信息。

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持凡科。



扫描二维码分享到微信

在线咨询
联系电话

020-66889888