1、验证签名
在提交配置时,服务器对应的URL需要实现签名的验证,成功时,需要直接返回 echostr 的值,注意此时URL对应的接口为get请求
const { signature, timestamp, nonce, echostr } = _req.query;
const token = "my_token"; // 公众号配置时的Token
const tmpArr = [token, timestamp, nonce];
tmpArr.sort();
// 引入加密模块
const crypto = require('crypto');
// 创建哈希对象
const sha1Hash = crypto.createHash('sha1');
// console.log("排序后连接:", tmpArr.join(""))
sha1Hash.update(tmpArr.join(""));
const hashedData = sha1Hash.digest('hex');
// console.log(hashedData, signature);
if (hashedData == signature) {
res.end(echostr);
}
2、消息推送
在用户操作时(关注、取消关注、扫描公众号二维码码等操作时),微信公众号会发送消息到基本配置中的URL对应的接口,注意此时URL对应的接口为post请求,也就是说URL对应的接口需要同时支持get和post请求。而且需要在IP白名单中添加服务器的IP地址。
3、完整示例
// router.js
var api = require('./api')
const bodyParser = require('body-parser')
const xmlParser = bodyParser.text({type: 'text/xml'});
// 验证微信公众号基本配置的URL
router.get('/receiveWeixinData', (req, res, next) => {
api.receiveWeixinData(req, res, next);
})
// 接收微信公众号推送过来的事件消息,和验证是同一个接口,不过使用的是post请求
router.post('/receiveWeixinData', xmlParser, (req, res, next) => {
api.receiveWeixinData(req, res, next);
})
// api.js
// 公众号基本配置URL
async receiveWeixinData(_req, res, _next) {
if (_req.query && _req.query["echostr"]) { // 用于配置时验证
// console.log("get验证接收到的参数:", _req.query);
const { signature, timestamp, nonce, echostr } = _req.query;
const token = "my_token"; // 公众号配置时的token
const tmpArr = [token, timestamp, nonce];
tmpArr.sort();
// 引入加密模块
const crypto = require('crypto');
// 创建哈希对象
const sha1Hash = crypto.createHash('sha1');
sha1Hash.update(tmpArr.join(""));
const hashedData = sha1Hash.digest('hex');
if (hashedData == signature) {
res.end(echostr);
} else {
res.end(false);
}
} else { // 用于平时扫码接收和发送消息
const xml = _req.body;
const xml2js = require('xml2js'); // xml2js需要npm先安装
xml2js.parseString(xml, { trim: true }, async (err, result) => {
if (err) {
console.error(err);
res.status(500).send('Internal Server Error');
return;
}
const message = result.xml;
// console.log("推送消息:", message)
let time = Math.floor(new Date().getTime() / 1000);
let content = '登录成功,欢迎使用简单设计!';
if (message.MsgType[0] === 'event') {
// 处理事件推送
const eventType = message.Event[0];
let eventKey = message.EventKey[0]; // 这个是获取公众号二维码的时候定义的,在获取ticket的时候,传给公众号接口就可定义这个scene_str
let user_id = message.FromUserName[0];
let checkRes = '';
switch (eventType) {
case 'subscribe':
// 处理关注事件
console.log('首次关注')
break;
case 'unsubscribe':
// 处理取消关注事件
console.log('取消关注')
break;
case 'SCAN':
// 关注后的扫码,前面会带qrscene_前缀
if (eventKey.includes('qrscene_')) {
eventKey = eventKey.replace('qrscene_', '');
}
console.log("扫码了")
break;
}
}
// 这个是扫码后,在公众号回复给用户看的,注意ToUserName是接收时的FromUserName,FromUserName是接收时的ToUserName
let returnXml =
`<xml><ToUserName><![CDATA[${message.FromUserName[0]}]]></ToUserName>
<FromUserName><![CDATA[${message.ToUserName[0]}]]></FromUserName>
<CreateTime>${time}</CreateTime>
<MsgType><![CDATA[text]]></MsgType>
<Content><![CDATA[登录成功,欢迎使用简单设计!]]></Content>
</xml>`;
res.send(returnXml);
});
}
},
https://jiandan.link/#/
2592

被折叠的 条评论
为什么被折叠?



