一, 服务器有效性验证
- 首先参考:微信公众号接入服务器指南.进行配置一些服务器的信息
- 微信开放文档未提供node版的验证服务器地址有效性的代码示例,此代码也可通过微信提供的其他代码示例来写出node版示例。
var crypto = require("crypto"); function sha1(str){ var md5sum = crypto.createHash("sha1"); md5sum.update(str); str = md5sum.digest("hex"); return str; } function validateToken(req,res){ var query = req.query;//express创建的服务器 //var query = url.parse(req.url,true).query;//通过http创建的服务器 console.log(query); var signature = query.signature;//微信加密签名 var echostr = query.echostr;//随机字符串 var timestamp = query['timestamp'];//时间戳 var nonce = query.nonce;//随机数 var oriArray = new Array(); oriArray[0] = nonce; oriArray[1] = timestamp; oriArray[2] = "myserty";//这里是你在微信开发者中心页面里填的token //1.将token、timestamp、nonce三个参数进行字典序排序 oriArray.sort(); var original = oriArray.join('');//把排序后的数组转换为字符串 //2.将三个参数字符串拼接成一个字符串进行sha1加密 var scyptoString = sha1(original); //3.开发者获得加密后的字符串与signature对比,判断该请求是否来源于微信 if(signature == scyptoString){ //4.若确认此次GET请求来自微信服务器,请原样返回echostr参数内容,则接入生效,成为开发者成功,否则接入失败。 res.end(echostr); }else { res.end("false"); } } module.exports = { validateToken };
var express = require('express'); var router = express.Router(); const { validateToken } = require('../utils/weixin.js'); router.get('/', function(req, res) { validateToken(req,res); });
- 参考地址:
node版示例代码
express服务器快速创建 - 我提炼出的过程为:
- 微信服务器根据开发者填写的token参数,请求中的timestamp参数、nonce参数,进行加密生成signature签名。
- 微信服务器将发送GET请求到开发者提供的服务器地址URL上,并携带signature参数(微信加密签名),timestamp参数(时间戳),nonce参数(随机数),echostr参数(随机字符串)。
-
示例:GET /?signature=0c1f56bb94241393e83fe733379ba9bcb2d94d09&echostr=5735277558564388844×tamp=1584954856&nonce=441827227 200 15.850 ms - -
- 根据微信校验流程:
- 将token、timestamp、nonce三个参数进行字典序排序
- 将三个参数字符串拼接成一个字符串进行sha1加密
- 开发者获得加密后的字符串可与signature对比,标识该请求来源于微信
- 对比成功后,原样返回echostr参数内容。
- 微信服务器收到之后,如果等于服务器本身设定的那个值,就通过验证。
二,消息的收发
- 当微信用户向公众号账号发送消息时,微信服务器将POST消息的XML数据包发送到开发者填写的URL上
<xml> <!--发送的xml数据包格式--> <ToUserName><![CDATA[toUser]]></ToUserName> <FromUserName><![CDATA[fromUser]]></FromUserName> <CreateTime>1348831860</CreateTime> <MsgType><![CDATA[text]]></MsgType> <Content><![CDATA[this is a test]]></Content> <MsgId>1234567890123456</MsgId> </xml> <!--toUser:开发者微信号--> <!--fromUser:发送方帐号(一个OpenID)--> <!--CreateTime:消息创建时间 (整型)--> <!--MsgType:消息类型,文本为text--> <!--Content:文本消息内容--> <!--MsgId:消息类型,消息id,64位整型-->
- 示例代码:
<xml> <ToUserName><![CDATA[gh_9afe90ec****]]></ToUserName> <FromUserName><![CDATA[o91bkwKk8n3dIxoad6sfHhUL****]]></FromUserName> <CreateTime>1584957185</CreateTime> <MsgType><![CDATA[text]]></MsgType> <Content><![CDATA[HR]]></Content> <MsgId>22691129132250277</MsgId> </xml>
- 之前通过body-parser用req.body直接获取微信传递过来的数据包(XML),发现获取不到(为一个空对象),原因是body-parser只对req.body 为json格式的做解析,所以对于xml格式的,解析后就req.body就变成空对象了。
- 通过百度查找到了两个xml转化模块:xml2js与express-xml-bodyparser
- 因为我使用的为express,而且只需要在请求中调用转换,所以选择express-xml-bodyparser
function sendMsg(req,res){ var query = req.body.xml; console.log(query); let msg = ` <xml> <ToUserName><![CDATA[${query.fromusername}]]></ToUserName> <FromUserName><![CDATA[${query.tousername}]]></FromUserName> <CreateTime>${query.timestamp}</CreateTime> <MsgType><![CDATA[text]]></MsgType> <Content><![CDATA[你好]]></Content> </xml> ` /* ToUserName:接收方帐号 FromUserName:开发者微信号 CreateTime:消息创建时间 (整型) MsgType:消息类型,文本为text Content:文本消息内容 */ //注意返回的数据也必须为XML结构 res.end(msg); } module.exports = { sendMsg };
通过express-xml-bodyparser解析后的数据包var express = require('express'); var xmlparser = require('express-xml-bodyparser'); var router = express.Router(); const { sendMsg } = require('../utils/wei.js'); router.post('你设置的公众号URL',xmlparser({trim: false, explicitArray: false}), function(req, res) { sendMsg(req,res); });
{ tousername: 'gh_9afe90ec****', fromusername: 'o91bkwKk8n3dIxoad6sfHhUL****', createtime: '1584958735', msgtype: 'text',//消息类型 content: '你好',//发送的消息内容 msgid: '22691153806695561' }