代码之外
前言
最近做项目, 需要用nodejs开发weixin的自动回复系统(包括菜单事件什么的, 在github上简单看了一些库, 发现都有一个类似的bug. 每当用户发送消息的时候, 微信服务器都会向我们的nodejs服务器发送一个POST请求, 包括 node-wechat, weixin_api, node-weixin, 在收到 POST 请求之后将请求的 response 设置在全局位置, 这样在多条消息同时到来的时候会有问题. 先来的消息很有可能会通过后面的 response 发送消息. 这个问题我和 node-wechat 的作者 nswbmw 提出了, 他好心的要修改一下, 但是,我现在很立刻就需要呀~ 所以就自己动手了. 写的时候也参考了文中提到的三个库的优缺点, 在此一并谢过~ 高级功能会在日后逐渐完善, 希望有好心人一起完整其他功能~
注意事项
- 有的时候同一条消息会触发多次,是因为在 5s 内,你的服务器没有给weixin服务器相应,weixin服务器会在未来的有限时间内不断的向你的服务器发送同一条消息的请求。可以通过
MsgId
来判断是否为同一条消息
Nodejs Wechat
Nodejs wrapper of wechat api
Usage
Work with native http server
var http = require('http');
var xmlBodyParser = require('express-xml-parser');
var Wechat = require('nodejs-wechat');
var opt = {
token: 'TOKEN',
url: '/'
};
var parse = xmlBodyParser({
type: 'text/xml'
});
var wechat = new Wechat(opt);
wechat.on('event.subscribe', function(session) {
session.replyTextMsg('欢迎您关注我们的订阅号');
});
var server = http.createServer(function(req, res) {
if (req.method === 'GET') {
wechat.verifyRequest(req, res);
} else {
parse(req, res, function(err) {
if (err) {
res.end();
return;
}
wechat.handleRequest(req, res);
});
}
});
server.listen(80);
Work with express
var express = require('express');
var app = express();
var middlewares = require('express-middlewares-js');
app.use('/weixin', middlewares.xmlBodyParser({
type: 'text/xml'
}));
/*
Alternative way
var xmlBodyParser = require('express-xml-parser');
app.use('/weixin', xmlBodyParser({
type: 'text/xml',
limit: '1mb'
}));
*/
var Wechat = require('nodejs-wechat');
var opt = {
token: token,
url: '/weixin'
};
var wechat = new Wechat(opt);
app.get('/weixin', wechat.verifyRequest.bind(wechat));
app.post('/weixin', wechat.handleRequest.bind(wechat));
// you can also work with other restful routes
app.use('/api', middlewares.bodyParser());
wechat.on('text', function(session) {
session.replyTextMsg('Hello World');
});
wechat.on('image', function(session) {
session.replyNewsMsg([{
Title: '新鲜事',
Description: '点击查看今天的新鲜事',
PicUrl: 'http://..',
Url: 'http://..'
}]);
});
wechat.on('voice', function(session) {
session.replyMsg({
Title: 'This is Music',
MsgType: 'music',
Description: 'Listen to this music and guess ths singer',
MusicUrl: 'http://..',
HQMusicUrl: 'http://..',
ThumbMediaId: '..'
});
});
app.listen(80);
NOTE: We apply
{ type: 'text/xml' }
toxmlBodyParser
as weixin server send us atext/xml
content type instead ofapplication/xml
.
API
-
#verifyRequest(req, res)
This is a express/connect middleware, which verify the signature of request from weixin server
-
#handleRequest(req, res)
This is a express/connect middleware, which handle the request post from weixin server
-
#on(msgType, handler)
Wechat is an inheritance from event.EventEmitter. Wechat will emit an event in incoming message’s
MsgType
, with aSession
as parameter. Valid events:text
,image
,voice
,video
,location
,link
,event.subscribe
,event.unsubscribe
,event.SCAN
,event.LOCATION
,event.CLICK
,event.VIEW
,error
Session
incomingMessage
This is a direct parse of weixin server request
<xml>
<ToUserName><![CDATA[toUser]]></ToUserName>
<FromUserName><![CDATA[FromUser]]></FromUserName>
<CreateTime>123456789</CreateTime>
<MsgType><![CDATA[event]]></MsgType>
<Event><![CDATA[subscribe]]></Event>
</xml>
Becomes
{
"ToUserName": "toUser",
"FromUserName": "FromUser",
"CreateTime": "123456789",
"MsgType": "event",
"Event": "subscribe"
}
-
req
This is the request from weixin server
-
res
This is the response to weixin server
-
#replyMsg(msgObject)
Reply a message via
this.res
-
#replyTextMessage(content)
Reply a text message
-
#replyNewsMessage(articles)
Reply a news messages.
TODO
- Advanced interfaces
Will finish advanced interfaces before July/2014, welcome send pull requests :)