当准备工作完成的时候,先来一个简单的功能,回复一个固定的消息,大致就是当用户关注该公众号的时候,公众号会回复一则文本消息。
在开始之前呢,首先概述一下这篇文章的重点,第一,公众号的取消、关注、用户发送的内容都是POST请求;第二,公众号发送的内容不是json格式,而是xml格式,是不是有点脑壳疼;第三,返回给用户的消息格式也是xml格式。
在这里,我采用raw-body及xml2js模块来将xml数据格式转换为json。
//g.js部分代码
const sha1=require('sha1');
const getRawBody=require('raw-body');
const util=require('./util');
module.exports=function(opts){
var wechat=new WeChat(opts);
return async function(ctx){
const signature=ctx.query.signature,
timestamp=ctx.query.timestamp,
nonce=ctx.query.nonce,
token=opts.token;
//字典排序
const str=[token,timestamp,nonce].sort().join('');
const result=sha1(str);
if(result===signature){
if(ctx.request.method==="GET"){
ctx.body=ctx.query.echostr;
}else if(ctx.request.method==="POST"){
try{
var data=await getRawBody(ctx.req,{
length: ctx.request.length,
limit: "1mb",
encoding: ctx.request.charset
});
var content=await util.parseXMLAsync(data);
console.log(content);
}catch(err){
console.log(err);
}
}
}else{
ctx.body={
code:-1,
msg:"fail"
}
}
}
}
//util.js部分代码
var xml2js=require('xml2js');
exports.parseXMLAsync=function(xml){
return new Promise((resolve,reject)=>{
xml2js.parseString(xml,{trim:true},function(err,content){
if(err){
reject(err);
}
resolve(content);
});
});
}
当我关注公众号的时候,可以发现控制台打印结果如下图所示:
打印结果
很容易发现这个数据仍然不是最终想要的json格式,因为它的每一个值都是个数组格式,所以需要再在util.js当中增加一个方法来将这种数据转换为需要的格式。
function formatMessage(result){
var message={};
if(typeof result ==='object'){
var keys=Object.keys(result);
for(let i=0;i<keys.length;i++){
var item=result[keys[i]];
var key=keys[i];
if(!(item instanceof Array) || item.length===0){
continue;
}
else if(item.length===1){
var val=item[0];
if(typeof val === 'object'){
messgae[key]=formatMessage(val);
}else{
message[key]=(val || '').trim();
}
}
else{
message[key]=[];
for(var j=0,k=item.length;j<k;j++){
message[key].push(formatMessage(item[j]));
}
}
}
}
return message;
}
exports.formatMessage=formatMessage
最后就是返回消息内容了,具体的返回格式可参考公众号官方文档。
if(result===signature){
if(ctx.request.method==="GET"){
ctx.body=ctx.query.echostr;
}else if(ctx.request.method==="POST"){
try{
var data=await getRawBody(ctx.req,{
length: ctx.request.length,
limit: "1mb",
encoding: ctx.request.charset
});
var content=await util.parseXMLAsync(data);
var message=util.formatMessage(content.xml);
if(message.MsgType==='event'){
if(message.Event==='subscribe'){//关注
var now = Date.parse(new Date())/1000;
ctx.type='application/xml';
var reply=`<xml>
<ToUserName><![CDATA[${message.FromUserName}]]></ToUserName>
<FromUserName><![CDATA[${message.ToUserName}]]></FromUserName>
<CreateTime>${now}</CreateTime>
<MsgType><![CDATA[text]]></MsgType>
<Content><![CDATA[终于等到你,还好我没放弃,欢迎关注lk儒家测试公众号!]]></Content>
</xml>`;
ctx.body=reply;
}
}
}catch(err){
console.log(err);
}
}
}else{
ctx.body={
code:-1,
msg:"fail"
}
}
网友评论