微信开发模式为什么消息有时回不到手机上
我的微信程序不知道为什么总是不能正常回发到用户手机上,从收到微信POST信息到服务器res.send发送完数据,时间基本在100毫秒内,请老师们帮帮我,检查一下我的问题
//这是调用过程
var weixin = require('./wechat');
weixin.on('TextMsg', function (aweixin) { //收到text消息
var msg = aweixin.makeMsg({MsgType: 'text', Content: "这是测试信息"});
在这里把msg保存起来
aweixin.res.send(msg); //这次发送手机基本上收不到,极少数能收到
})
app.post('/weixin', function (req, res) {
// 这里判断如果是重试的请求,就把上次保存的消息直接发出去,基本上都能收到
if (重复) return res.send(保存的msg);
//如果不重复,开始构造一个weixin,并处理微信发来的消息
var aweixin = new weixin({req: req, res: res, token: token, secret: encodingaeskey, appid: corpid})
aweixin.exec();
});
// 以下是微信模块 // wechat.js
var sha1 = require('sha1');
var xml2js = require('xml2js');
var Events = require('events');
var emitter = new Events.EventEmitter();
var request = require('request');
var crypto = require('crypto');
var XMLParser = require('xml2js');
// thunkify = require('thunkify');
var buildXML = new XMLParser.Builder({rootName:'xml',cdata:true,headless:true,renderOpts :{indent:' ',pretty:'true'}});
var msglist = [];
var Weixin = function (options) {
this.req = options.req;
this.res = options.res;
this.res.setCharacterEncoding("UTF8");
if (this.cf()) return; //如果重复直接退出
this.req.query.msg_signature = this.req.query.msg_signature || this.req.query.signature;
this.token = options.token || '';
this.appID = options.appid || '';
this.secret = options.secret || '';
this.aesKey = new Buffer(this.secret + '=', 'base64');
this.iv = this.aesKey.slice(0, 16);
this.accessToken = '';
};
Weixin.prototype.indexofsig = function (sig) { //按签名查找已存在消息
if (sig==undefined) sig = this.req.query.msg_signature;
for (var i=0; i < msglist.length; i++) {
while (true) {
if (parseInt(new Date().valueOf() / 1000) - msglist[i].attime > 15) { //删除超过10秒的信息
msglist.splice(i, 1);
if (i<msglist.length) continue; else break;
}
if (msglist[i].sig == sig) {
return i;
}
break;
}
}
};
Weixin.prototype.cf = function (sig) { //查消息是否重复
return (this.indexofsig(sig) >= 0);
};
Weixin.prototype.msgofsig = function (sig) { //返回重复的消息
return msglist[this.indexofsig(sig)];
};
Weixin.prototype.removesig = function (sig) { //按签名删除超时的消息
msglist.splice(this.indexofsig(sig),1);
};
/**
* 执行
* [@param](/user/param) fb 回调
* [@returns](/user/returns) {Weixin}
*/
Weixin.prototype.exec = function (fb) {
var _this = this;
msglist.push({sig:_this.req.query.msg_signature,attime:parseInt(new Date().valueOf() / 1000)});//保存到消息列表中
_this.req.postdata(function(data){
_this.parseXmltoJson(data, function (err, data) {
if ((!_this.req.query.nosig) && (false == _this.verifysignature(_this.req.query.timestamp, _this.req.query.nonce, data.Encrypt, _this.req.query.msg_signature))) {
if (fb) fb('验签未通过');
} else {
var execmsg = function (data) {
_this.msg = data;
_this.fromUser = _this.msg.FromUserName;
_this.toUser = _this.msg.ToUserName;
_this.analysisMsg();
};
if (!_this.req.query.nosig) {
_this.parseXmltoJson(_this.decrypt(data.Encrypt), function(err,data) {
execmsg(data)
});
} else
execmsg(data);
}
});
});
};
/**
* 回复消息
* [@param](/user/param) msg
*/
Weixin.prototype.makeMsg = function (msg) {
var MsgType = msg.MsgType;
var weixinTmpl = weixinMsgXml[MsgType];
var _timestamp = parseInt(this.req.query.timestamp);//用的微信发来的timestamp、nonce和createtime
var _nonce = parseInt(this.req.query.nonce);
var _createtime = parseInt(this.msg.CreateTime);
weixinTmpl = weixinTmpl.replace((new RegExp('{ToUserName}','g')),this.msg.FromUserName);
weixinTmpl = weixinTmpl.replace((new RegExp('{FromUserName}','g')),this.msg.ToUserName);
for (var k in msg) {
var reg = new RegExp('{' + k + '}', 'g');
weixinTmpl = weixinTmpl.replace(reg, msg[k]);
}
weixinTmpl = weixinTmpl.replace((new RegExp('{CreateTime}','g')),_createtime);
if (MsgType == 'news') {
var items = '';
for (var i = 0; i < msg.Articles.length; i++) {
var tmp = weixinMsgXml['item'];
for (var item in msg.Articles[i]) {
var regNews = new RegExp('{' + item + '}', 'g');
tmp = tmp.replace(regNews, msg.Articles[i][item]);
}
items += tmp;
}
weixinTmpl = weixinTmpl.replace('{ArticleCount}', Object.keys(msg.Articles).length);
weixinTmpl = weixinTmpl.replace('{items}', items);
}
weixinTmpl = this.encrypt(weixinTmpl); // 已生成XML消息,加密为Encrypt
// 拼接成要发的xml消息
weixinTmpl = "<xml>"+
"<Encrypt><![CDATA["+weixinTmpl+"]]></Encrypt>"+
"<MsgSignature><![CDATA["+
this.makesignature(_timestamp, _nonce, weixinTmpl)+
"]]></MsgSignature>"+
"<TimeStamp>"+_timestamp+"</TimeStamp>"+
"<Nonce><![CDATA["+_nonce+"]]></Nonce>"+
"</xml>";
if (this.indexofsig() >= 0) this.msgofsig().msg = weixinTmpl;
return weixinTmpl;
};
/* 生成签名 */
Weixin.prototype.makesignature = function (timestamp,nonce,Encrypt){
return sha1([this.token, timestamp, nonce, Encrypt].sort().join(''));
};
/* 比对签名是否正确
* 比较 signature 或 msg_signature
*/
Weixin.prototype.verifysignature = function (timestamp,nonce,Encrypt,signature) {
return (this.makesignature(timestamp,nonce,Encrypt) == (signature));
};
var weixinMsgXml = {
text: '<xml>' +
'<ToUserName><![CDATA[{ToUserName}]]></ToUserName>' +
'<FromUserName><![CDATA[{FromUserName}]]></FromUserName>' +
'<CreateTime>{CreateTime}</CreateTime>' +
'<MsgType><![CDATA[text]]></MsgType>' +
'<Content><![CDATA[{Content}]]></Content>' +
'</xml>',
image: '<xml>' +
'<ToUserName><![CDATA[{ToUserName}]]></ToUserName>' +
'<FromUserName><![CDATA[{FromUserName}]]></FromUserName>' +
'<CreateTime>{CreateTime}</CreateTime>' +
'<MsgType><![CDATA[image]]></MsgType>' +
'<Image>' +
'<MediaId><![CDATA[{MediaId}]]></MediaId>' +
'</Image>' +
'</xml>',
voice: '<xml>' +
'<ToUserName><![CDATA[{ToUserName}]]></ToUserName>' +
'<FromUserName><![CDATA[{FromUserName}]]></FromUserName>' +
'<CreateTime>{CreateTime}</CreateTime>' +
'<MsgType><![CDATA[voice]]></MsgType>' +
'<Voice>' +
'<MediaId><![CDATA[{MediaId}]]></MediaId>' +
'</Voice>' +
'</xml>',
video: '<xml>' +
'<ToUserName><![CDATA[{ToUserName}]]></ToUserName>' +
'<FromUserName><![CDATA[{FromUserName}]]></FromUserName>' +
'<CreateTime>{CreateTime}</CreateTime>' +
'<MsgType><![CDATA[video]]></MsgType>' +
'<Video>'+
'<MediaId><![CDATA[{MediaId}]]></MediaId>'+
'<ThumbMediaId><![CDATA[{ThumbMediaId}]]></ThumbMediaId>' +
'</Video>'+
'</xml>',
music: '<xml>' +
'<ToUserName><![CDATA[{ToUserName}]]></ToUserName>' +
'<FromUserName><![CDATA[{FromUserName}]]></FromUserName>' +
'<CreateTime>{CreateTime}</CreateTime>' +
'<MsgType><![CDATA[music]]></MsgType>' +
'<Music>' +
'<Title><![CDATA[{Title}]]></Title>' +
'<Description><![CDATA[{Description}]]></Description>' +
'<MusicUrl><![CDATA[{MusicUrl}]]></MusicUrl>' +
'<HQMusicUrl><![CDATA[{HQMusicUrl}]]></HQMusicUrl>' +
'<ThumbMediaId><![CDATA[{ThumbMediaId}]]></ThumbMediaId>' +
'</Music>' +
'</xml>',
news: '<xml>' +
'<ToUserName><![CDATA[{ToUserName}]]></ToUserName>' +
'<FromUserName><![CDATA[{FromUserName}]]></FromUserName>' +
'<CreateTime>{CreateTime}</CreateTime>' +
'<MsgType><![CDATA[news]]></MsgType>' +
'<ArticleCount>{ArticleCount}</ArticleCount>' +
'<Articles>' +
'{items}' +
'</Articles>' +
'</xml>',
item: '<item>' +
'<Title><![CDATA[{Title}]]></Title>' +
'<Description><![CDATA[{Description}]]></Description>' +
'<PicUrl><![CDATA[{PicUrl}]]></PicUrl>' +
'<Url><![CDATA[{Url}]]></Url>' +
'</item>'
};
/**
* 接收消息解析
*/
Weixin.prototype.analysisMsg = function () {
var _this = this;
if (this.err) {
this.handleMsgErr();
} else {
var MsgType = this.msg.MsgType.toLowerCase();
switch (MsgType) {
// MsgErr 错误消息
// clickEventMsg 自定义菜单事件
case 'text':
emitter.emit('TextMsg', this); //文本消息
break;
case 'image':
emitter.emit('ImageMsg'); //图片消息
break;
case 'voice':
emitter.emit('VoiceMsg'); //语音消息
break;
case 'video':
emitter.emit('VideoMsg'); //视频消息
break;
case 'location':
emitter.emit('LocationEventMsg', _this);//地理位置消息
// emitter.emit('LocationMsg');//地理位置消息
break;
case 'link':
emitter.emit('LinkMsg'); //链接消息
break;
case 'event': //事件消息
switch (this.msg.Event.toLowerCase()) {
case 'location':
emitter.emit('LocationEventMsg', _this); // 上报位置事件
break;
case 'click':
emitter.emit('clickEventMsg', this); // 单击事件
break;
case 'enter':
emitter.emit('EnterEventMsg', this); // 进入会话事件
break;
case 'scan':
emitter.emit('ScanEventMsg', this); // 扫码事件
break;
case 'subscribe':
emitter.emit('SubEventMsg', this); // 订阅事件
break;
case 'unsubscribe':
emitter.emit('UnSubEventMsg', this); // 取消订阅事件
break;
}
break;
}
}
};
Weixin.on = function (msgstr, cb) {
emitter.on(msgstr,cb);
return this;
};
Weixin.prototype.parseXmltoJson = function (strXml, fb) {
xml2js.parseString(strXml.toString(), {explicitArray: false}, function (err, json) {
if (err)
fb(err);
else
fb(null,json.xml);
});
};
/* 解密 */
Weixin.prototype.decrypt = function (str) {
var aesCipher = crypto.createDecipheriv("aes-256-cbc", this.aesKey, this.iv);
aesCipher.setAutoPadding(false);
var decipheredBuff = Buffer.concat([aesCipher.update(str, 'base64'), aesCipher.final()]);
decipheredBuff = PKCS7Decoder(decipheredBuff);
var len_netOrder_corpid = decipheredBuff.slice(16);
var msg_len = len_netOrder_corpid.slice(0, 4).readUInt32BE(0);
//recoverNetworkBytesOrder(len_netOrder_corpid.slice(0, 4));
var result = len_netOrder_corpid.slice(4, msg_len + 4).toString();
var appId = len_netOrder_corpid.slice(msg_len + 4).toString();
if (appId != this.appID)throw new Error('appId is invalid');
return result;
};
function PKCS7Decoder(buff) {
var pad = buff[buff.length - 1];
if (pad < 1 || pad > 32) {
pad = 0;
}
return buff.slice(0, buff.length - pad);
}
//加密
Weixin.prototype.encrypt = function (xmlMsg) {
var random16 = crypto.pseudoRandomBytes(16);
var msg = new Buffer(xmlMsg);
var msgLength = new Buffer(4);
msgLength.writeUInt32BE(msg.length, 0);
var corpId = new Buffer(this.appID);
var raw_msg = Buffer.concat([random16,msgLength,msg ,corpId]);//randomString + msgLength + xmlMsg + this.corpID;
var encoded = PKCS7Encoder(raw_msg);
var cipher = crypto.createCipheriv('aes-256-cbc', this.aesKey, this.iv);
// cipher.setAutoPadding(true);
var cipheredMsg = Buffer.concat([cipher.update(encoded/*raw_msg*/), cipher.final()]);
return cipheredMsg.toString('base64');
};
function PKCS7Encoder(buff) {
var blockSize = 32;
var strSize = buff.length;
var amountToPad = blockSize - (strSize % blockSize);
var pad = new Buffer(amountToPad-1);
pad.fill(String.fromCharCode(amountToPad));
return Buffer.concat([buff, pad]);
}
module.exports = Weixin;```
6 回复
请你先markdown
@haozxuan 谢谢,markdown是什么东西?我百度了好像是一个软件!
@jinhx 格式化下你贴出来的东西,自己看着都不舒服,别人没办法帮你;
@haozxuan 加上了
@haozxuan 就是一般的res的发送方法,我把req和res都附加到aweixin里去了,方便操作
* 发送一般数据
* @param data
* @param type
*/
function res_send(data,type) {
if (!type)
this.writeHead(200,{});
else
this.writeHead(200,{"Content-Type": type});
this.write(data);
this.end();
}