node(egg)完成微信公众号自动回复功能
项目背景:
我这里是在使用微信公众号获取用户openid的时候希望不经过网页授权方式获取。所以就想到通过事件消息推送的方式来进行,也就是说用户关注,取消关注,发送消息,返回回来的数据都会携带openid,这是我想要的。这边使用的是node来作为服务端
1.首先需要在微信公众平台 - 基础设置 - 设置服务器地址
image.png image.png2.配置服务器地址时可能出现“参数错误,。。。。”的情况,可能是因为域名被拦截,不能使用。
那么首先就需要在后台实现这么个接口来开启这个url接口。这个地方填写服务器地址接口域名,就是用来跟公众号交互的。
首先实现一个get请求通过这个配置鉴权
async index() {
const { ctx, app } = this;
let { signature, echostr, timestamp, nonce } = ctx.query;
console.log(ctx.query)
const token = 'zwp123'; // 这个地方就是公众平台上所谓的token 必须一样
// 将token、timestamp、nonce三个参数进行字典序排序
const arr = [token, timestamp, nonce];
arr.sort();
// 将三个参数字符串拼接成一个字符串进行sha1加密
const str = arr[0]+ arr[1] + arr[2];
var sha1 = require('sha1');
console.log(sha1(str))
// 开发者获得加密后的字符串可与signature对比
if(sha1(str) === signature){
ctx.body = echostr;
}else{
ctx.body = false;
}
}
配置好服务器地址等信息,提交成功,点击启用完成服务器配置
3. 回复消息,分为关注后自动回复以及粉丝向公众号发消息时的回复等等情况
如何捕获用户。实际上都是微信服务器post请求配置好的服务器地址
async index2() {
const { ctx, app } = this;
console.log(this.ctx.request.body)
// 用xml2js模块来处理xml
var parseString = require('xml2js').parseString;
var xml = this.ctx.request.body;
parseString(xml, function (err, result) {
// console.log(result.xml)
const xmlData = result.xml;
const createTime = Date.parse(new Date());
const msgType = xmlData.MsgType[0]; // 消息类型,event
const toUserName = xmlData.ToUserName[0]; // 开发人员微信号
const toFromName = xmlData.FromUserName[0]; // 发送方帐号(一个OpenID)
const event = xmlData.Event ? xmlData.Event[0] : ''; // 事件类型,subscribe(订阅)、unsubscribe(取消订阅)
console.log(event)
if(msgType == 'event' && event == 'subscribe'){ // 关注后
ctx.body = `<xml>
<ToUserName><![CDATA[${toFromName}]]></ToUserName>
<FromUserName><![CDATA[${toUserName}]]></FromUserName>
<CreateTime>${createTime}</CreateTime>
<MsgType><![CDATA[text]]></MsgType>
<Content><![CDATA[欢迎关注w满城不及她公众号,下面请开始你的表演!]]></Content>
</xml>`;
}
else{// 其他情况
ctx.body = `<xml>
<ToUserName><![CDATA[${toFromName}]]></ToUserName>
<FromUserName><![CDATA[${toUserName}]]></FromUserName>
<CreateTime>${createTime}</CreateTime>
<MsgType><![CDATA[text]]></MsgType>
<Content><![CDATA[啊~啊~啊~你在发什么消息?]]></Content>
</xml>`;
}
})
}
来解释下,当用户点击关注,取消,发送消息的时候,会调用post接口推送xml数据信息,格式如下所示
<xml>
<ToUserName><![CDATA[gh_a0df2b564971]]></ToUserName>
<FromUserName><![CDATA[opNck1VdVevJsMeTfICgyHpW-Y_k]]></FromUserName>
<CreateTime>1604312087</CreateTime>
<MsgType><![CDATA[event]]></MsgType>
<Event><![CDATA[subscribe]]></Event>
<EventKey><![CDATA[]]></EventKey>
</xml>
在使用node的过程中打印接收body里面的数据为空,这是格式位xml数据,需要进行处理,我这里用的egg。
解决办法:config.default.js 文件中配置
// 覆盖egg自带的配置 使支持接收xml参数
config.bodyParser = {
enable: true,
encoding: 'utf8',
formLimit: '100kb',
jsonLimit: '100kb',
strict: true,
// @see https://github.com/hapijs/qs/blob/master/lib/parse.js#L8 for more options
queryString: {
arrayLimit: 100,
depth: 5,
parameterLimit: 1000,
},
enableTypes: ['json', 'form', 'text'],
extendTypes: {
text: ['text/xml', 'application/xml'],
},
};
这样就能看到xml数据了。
再然后就要去解析xml数据了,我这里用到了一个插件xml2js
地址:https://www.npmjs.com/package/xml2js
安装:
npm i xml2js
简单用法:
var parseString = require('xml2js').parseString;
var xml = "<root>Hello xml2js!</root>"
parseString(xml, function (err, result) {
console.dir(result);
});
再解析数据后就可以捕获用户的动作,返回各种信息了
image.png
image.png
这样就好了。
注意:我这里配置的路由是这样的
// 公众号测试
router.get('/index', controller.demo.index);
router.post('/index', controller.demo.index2);
可以看到是相同的接口名称,只是接口请求方式不一样,一个是get,一个是post
get请求是用来通过配置服务器地址的
post请求是用来捕获用户在微信公众号各种操作的
可能讲的不是清楚,请见谅,也是这两天才琢磨出来的,因此记录下来,以便后续不忘记
推荐文章:
https://www.cnblogs.com/kakayang/p/9729541.html
https://blog.csdn.net/m0_37805167/article/details/84327354