一、寫在前面的話
當用戶發送消息給公眾號時(或某些特定的用戶操作引發的事件推送時),會產生一個POST請求,開發者可以在響應包(Get)中返回特定XML結構,來對該消息進行響應。
消息推送也是微信公眾號開發更為有趣的功能,涉及到文本消息、圖片消息、語音消息、視頻消息、音樂消息以及圖文消息。並且最為有趣的功能當屬消息加解密了,當然由於篇文章篇幅的原因我會在下一篇文章中去着重說明。
二、微信消息管理
1.捕獲消息信息
在文章的第一句話中,為我們指明了微信消息產生的請求方式為 POST,因此首先我們就去對 Node.js 的 Post 請求進行監聽。
在我們的 app.js 文件中添加一個POST監聽,並將獲取的結果輸出:
//用於處理所有進入 3000 端口 post 的連接請求
app.post('/',function(req,res){
var buffer = [];
//監聽 data 事件 用於接收數據
req.on('data',function(data){
buffer.push(data);
});
//監聽 end 事件 用於處理接收完成的數據
req.on('end',function(){
//輸出接收完成的數據
console.log(Buffer.concat(buffer).toString('utf-8'));
});
});
隨后將 Node.js 啟動后映射至外網,關注我們的微信公眾號,在控制台中則會看到:
打開 微信幫助文檔 ,點擊左側菜單的消息管理,選擇其子菜單 接收事件推送,如圖:
從上圖我們不難看出,微信 接收事件推送 確實很多,而我們最終目標是要實現,在用戶觸發事件時返回其相應的回復消息。因此我們總結一下我們要實現的步驟:
- 解析 XML ,使用 Event 參數判斷事件類型
- 返回相應的事件信息
總結完實現步驟后,我們就開始動手實現第一個被動回復消息吧。
2.以關注事件為例,實現第一個被動回復
解析 XML 我這里使用了 第三方的包 xml2js(npm install xml2js ),並在 wechat.js 中引入。
parseString = require('xml2js').parseString;//引入xml2js包
為 WeChat 對象添加一個消息處理的方法 handleMsg,將 app.js 中捕獲 POST 實現的寫入在其代碼塊中,並使用 xml2js 解析,代碼如下
/**
* 微信消息
*/
WeChat.prototype.handleMsg = function(req,res){
var buffer = [];
//監聽 data 事件 用於接收數據
req.on('data',function(data){
buffer.push(data);
});
//監聽 end 事件 用於處理接收完成的數據
req.on('end',function(){
var msgXml = Buffer.concat(buffer).toString('utf-8');
//解析xml
parseString(msgXml,{explicitArray : false},function(err,result){
if(!err){
//打印解析結果
console.log(result);
}else{
//打印錯誤信息
console.log(err);
}
})
});
}
在 app.js 中調用 handleMsg 方法
//用於處理所有進入 3000 端口 post 的連接請求
app.post('/',function(req,res){
wechatApp.handleMsg(req,res);
});
完成了代碼的編寫后,將公眾號重新關注
最后打印為一個 JSON 格式的結果,也就是預示着我們第1步工作已經完成。下面開始我們的第2步,微信被動回復。
在文章的第一句話的后邊提到 開發者可以在響應包(Get)中返回特定XML結構,那么這個特定的 XML 結構在哪呢?再次打開微信幫助文檔 ,點擊左側菜單的消息管理,選擇其子菜單 被動回復消息,如圖:
直接來到 回復文本消息:
拿到回復文本消息格式后,我們就來為關注我們公眾號的同學打聲招呼吧。在 wechat 文件中 創建 msg.js 文件用於消息的管理。
並在 msg.js 中添加處理文本消息的接口,並在 wechat.js 中引用
'use strict' //設置為嚴格模式
//回復文本消息
exports.txtMsg = function(toUser,fromUser,content){
var xmlContent = "<xml><ToUserName><![CDATA["+ toUser +"]]></ToUserName>";
xmlContent += "<FromUserName><![CDATA["+ fromUser +"]]></FromUserName>";
xmlContent += "<CreateTime>"+ new Date().getTime() +"</CreateTime>";
xmlContent += "<MsgType><![CDATA[text]]></MsgType>";
xmlContent += "<Content><![CDATA["+ content +"]]></Content></xml>";
return xmlContent;
}
修改 wechat.js 中 handleMsg 方法
/**
* 微信消息
*/
WeChat.prototype.handleMsg = function(req,res){
var buffer = [];
//監聽 data 事件 用於接收數據
req.on('data',function(data){
buffer.push(data);
});
//監聽 end 事件 用於處理接收完成的數據
req.on('end',function(){
var msgXml = Buffer.concat(buffer).toString('utf-8');
//解析xml
parseString(msgXml,{explicitArray : false},function(err,result){
if(!err){
result = result.xml;
var toUser = result.ToUserName; //接收方微信
var fromUser = result.FromUserName;//發送仿微信
//判斷事件類型
switch(result.Event.toLowerCase()){
case 'subscribe':
//回復消息
res.send(msg.txtMsg(fromUser,toUser,'歡迎關注 hvkcoder 公眾號,一起斗圖吧'));
break;
}
}else{
//打印錯誤信息
console.log(err);
}
})
});
}
沒錯就是這么簡單。這里有個邏輯是這樣的 toUser 表示接收方,也就是咱們的微信公眾號;fromUser 表示發送方,也就是觸發事件的用戶。而我們要回復用戶時,此時 接收方 就是 觸發事件的用戶,而發送方則是 我們的微信公眾號。這塊比較繞,大家可以慢慢去理解。
由於我們還沒有對微信的素材管理進行講解,這里我們暫時跳過 圖片消息、語音消息、視頻消息、以及音樂消息。直接實現圖文消息的推送。
3.圖文消息
在 msg.js 文件中添加圖文XML模板
//回復圖文消息
exports.graphicMsg = function(toUser,fromUser,contentArr){
var xmlContent = "<xml><ToUserName><![CDATA["+ toUser +"]]></ToUserName>";
xmlContent += "<FromUserName><![CDATA["+ fromUser +"]]></FromUserName>";
xmlContent += "<CreateTime>"+ new Date().getTime() +"</CreateTime>";
xmlContent += "<MsgType><![CDATA[news]]></MsgType>";
xmlContent += "<ArticleCount>"+contentArr.length+"</ArticleCount>";
xmlContent += "<Articles>";
contentArr.map(function(item,index){
xmlContent+="<item>";
xmlContent+="<Title><![CDATA["+ item.Title +"]]></Title>";
xmlContent+="<Description><![CDATA["+ item.Description +"]]></Description>";
xmlContent+="<PicUrl><![CDATA["+ item.PicUrl +"]]></PicUrl>";
xmlContent+="<Url><![CDATA["+ item.Url +"]]></Url>";
xmlContent+="</item>";
});
xmlContent += "</Articles></xml>";
return xmlContent;
}
}
更改 wechat.js 文件中的 handleMsg 方法,將圖消息推送響應在點擊事件中
case 'click':
var contentArr = [
{Title:"Node.js 微信自定義菜單",Description:"使用Node.js實現自定義微信菜單",PicUrl:"http://img.blog.csdn.net/20170605162832842?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvaHZrQ29kZXI=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast",Url:"http://blog.csdn.net/hvkcoder/article/details/72868520"},
{Title:"Node.js access_token的獲取、存儲及更新",Description:"Node.js access_token的獲取、存儲及更新",PicUrl:"http://img.blog.csdn.net/20170528151333883?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvaHZrQ29kZXI=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast",Url:"http://blog.csdn.net/hvkcoder/article/details/72783631"},
{Title:"Node.js 接入微信公眾平台開發",Description:"Node.js 接入微信公眾平台開發",PicUrl:"http://img.blog.csdn.net/20170605162832842?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvaHZrQ29kZXI=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast",Url:"http://blog.csdn.net/hvkcoder/article/details/72765279"}
];
//回復圖文消息
res.send(msg.graphicMsg(fromUser,toUser,contentArr));
break;
點擊菜單下的 今日推薦
圖文推送就是這么簡單的被我們給實現了。
4.接收普通消息
微信除了為我們接收事件推送外,千萬不要忘了微信還能通過發送文字。而這一節我們也就來玩玩微信接收普通消息。
打開 微信幫助文檔 ,點擊左側菜單的消息管理,選擇其子菜單 接收普通消息,如圖:
依然如接收事件推送的套路,不同的是參數發生了改變,但這並步影響我們的開發,只需要幾步就能夠完美的解決。更改 wechat.js 文件 handleMsg方法,這里我先暫時只針對用戶輸入的文本消息做處理,其他的跟其類似。
//判斷消息類型
if(result.MsgType.toLowerCase() === "event"){
//判斷事件類型
switch(result.Event.toLowerCase()){
case 'subscribe':
//回復消息
var content = "歡迎關注 hvkcoder 公眾號,一起斗圖吧。回復以下數字:\n";
content += "1.你是誰\n";
content += "2.關於Node.js\n";
content += "回復 “文章” 可以得到圖文推送哦~\n";
res.send(msg.txtMsg(fromUser,toUser,''));
break;
case 'click':
var contentArr = [
{Title:"Node.js 微信自定義菜單",Description:"使用Node.js實現自定義微信菜單",PicUrl:"http://img.blog.csdn.net/20170605162832842?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvaHZrQ29kZXI=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast",Url:"http://blog.csdn.net/hvkcoder/article/details/72868520"},
{Title:"Node.js access_token的獲取、存儲及更新",Description:"Node.js access_token的獲取、存儲及更新",PicUrl:"http://img.blog.csdn.net/20170528151333883?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvaHZrQ29kZXI=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast",Url:"http://blog.csdn.net/hvkcoder/article/details/72783631"},
{Title:"Node.js 接入微信公眾平台開發",Description:"Node.js 接入微信公眾平台開發",PicUrl:"http://img.blog.csdn.net/20170605162832842?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvaHZrQ29kZXI=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast",Url:"http://blog.csdn.net/hvkcoder/article/details/72765279"}
];
//回復圖文消息
res.send(msg.graphicMsg(fromUser,toUser,contentArr));
break;
}
}else{
//判斷消息類型為 文本消息
if(result.MsgType.toLowerCase() === "text"){
//根據消息內容返回消息信息
switch(result.Content){
case '1':
res.send(msg.txtMsg(fromUser,toUser,'Hello !我的英文名字叫 H-VK'));
break;
case '2':
res.send(msg.txtMsg(fromUser,toUser,'Node.js是一個開放源代碼、跨平台的JavaScript語言運行環境,采用Google開發的V8運行代碼,使用事件驅動、非阻塞和異步輸入輸出模型等技術來提高性能,可優化應用程序的傳輸量和規模。這些技術通常用於數據密集的事實應用程序'));
break;
case '文章':
var contentArr = [
{Title:"Node.js 微信自定義菜單",Description:"使用Node.js實現自定義微信菜單",PicUrl:"http://img.blog.csdn.net/20170605162832842?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvaHZrQ29kZXI=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast",Url:"http://blog.csdn.net/hvkcoder/article/details/72868520"},
{Title:"Node.js access_token的獲取、存儲及更新",Description:"Node.js access_token的獲取、存儲及更新",PicUrl:"http://img.blog.csdn.net/20170528151333883?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvaHZrQ29kZXI=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast",Url:"http://blog.csdn.net/hvkcoder/article/details/72783631"},
{Title:"Node.js 接入微信公眾平台開發",Description:"Node.js 接入微信公眾平台開發",PicUrl:"http://img.blog.csdn.net/20170605162832842?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvaHZrQ29kZXI=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast",Url:"http://blog.csdn.net/hvkcoder/article/details/72765279"}
];
//回復圖文消息
res.send(msg.graphicMsg(fromUser,toUser,contentArr));
break;
default :
res.send(msg.txtMsg(fromUser,toUser,'沒有這個選項哦'));
break;
}
}
}
OK !至此我們就完成了微信消息管理的講解,似乎真的沒有什么難度。預留了一章,主要想要去細說一下說消息加解密,因為在網上涉及 Node.js 微信消息加解密的文章確實很少,微信幫助文檔給的案例也沒有 Node.js 的詳細說明。
最后文章代碼部分,由於網上編輯器的代碼換行做的不是很好可能有些亂,建議可以去我的 github 上查看源碼。
文章源代碼:https://github.com/SilenceHVK/wechatByNode 。對文章有不正確之處,請給予糾正。github源代碼請順手給個 Star,最后感謝您的閱讀。
文章目錄:
1.Node.js 接入微信公眾平台開發
2.Node.js access_token的獲取、存儲及更新
3.Node.js 自定義微信菜單
4.Node.js 微信消息管理