當用戶發送消息給公衆號時(或某些特定的用戶操做引起的事件推送時),會產生一個POST請求,開發者能夠在響應包(Get)中返回特定XML結構,來對該消息進行響應。javascript
消息推送也是微信公衆號開發更爲有趣的功能,涉及到文本消息、圖片消息、語音消息、視頻消息、音樂消息以及圖文消息。而且最爲有趣的功能當屬消息加解密了,固然因爲篇文章篇幅的緣由我會在下一篇文章中去着重說明。html
1.捕獲消息信息java
在文章的第一句話中,爲咱們指明瞭微信消息產生的請求方式爲 POST,所以首先咱們就去對 Node.js 的 Post 請求進行監聽。git
在咱們的 app.js 文件中添加一個POST監聽,並將獲取的結果輸出:github
//用於處理全部進入 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 啓動後映射至外網,關注咱們的微信公衆號,在控制檯中則會看到:
npm
打開 微信幫助文檔,點擊左側菜單的消息管理,選擇其子菜單 接收事件推送,如圖:
微信
從上圖咱們不難看出,微信 接收事件推送 確實不少,而咱們最終目標是要實現,在用戶觸發事件時返回其相應的回覆消息。所以咱們總結一下咱們要實現的步驟:app
總結完實現步驟後,咱們就開始動手實現第一個被動回覆消息吧。微信公衆平臺
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 微信消息管理