上一篇文章:nodejs微信公眾號開發(1)接入微信公眾號,本篇文章將在此基礎上實現簡單的回復功能。
1. 接入代碼的優化
之前我們簡單粗暴的實現了微信公眾號的接入,接入的代碼直接寫在了app.js文件里面,從項目開發的角度而言,不便于日后代碼的維護,所以將這部分代碼獨立出來,按照koa的風格,寫成一個中間件。
在根目錄下新建wechat文件夾,新建generator.js文件,
var sha1 = require('sha1');module.exports = function(opts){  return function *(next){    var token = opts.token;    var signature = this.query.signature;    var nonce = this.query.nonce;    var timestamp = this.query.timestamp;    var echostr = this.query.echostr;    var str = [token,timestamp,nonce].sort().join('');    var sha = sha1(str);    this.body = (sha === signature) ? echostr + '' : 'failed';  };}此時app.js的內容變成:
'use strict'var Koa = require('koa');var wechat = require('./wechat/generator');var config = {  wechat:{    appID:'...',    appSecret:'...',    token:'...'  }};var app = new Koa();app.use(wechat(config.wechat));app.listen(8080);console.log('Listening 8080...')2. 獲取access_token
access_token是開發程序與wexin公眾平臺交互的一把鑰匙,調用絕大部分接口都需要用到access_token。
access_token的特點:
解決方案:
程序中采用構造函數的方式,在生成實例,完成初始化工作的的過程中,讀取存儲在config/wechat.txt文件中的票據,判斷是否為空且是否過期,選擇性的重新獲取數字并且保存在原文件里面,關于獲取access_token的官方文檔介紹可見:獲取access_token。
function Wechat(opts){   //構造函數,用以生成實例,完成初始化工作,讀寫票據  var that = this;  this.appID = opts.appID;  this.appSecret = opts.appSecret;  this.getAccessToken = opts.getAccessToken;  this.saveAccessToken = opts.saveAccessToken;  this.getAccessToken().then(function(data){    try{      data = JSON.parse(data);    }catch(e){      return that.updateAccessToken();    }    if(that.isvalidAccessToken(data)){      Promise.resolve(data);    }else{      return that.updateAccessToken();    }  }).then(function(data){    that.access_token = data.access_token;    that.expires_in = data.expires_in;    that.saveAccessToken(JSON.stringify(data));  });}我們在moudle.exports中實例化一個Wechat:
var wechat = new Wechat(opts);
這樣確保了每次程序啟動都會獲取對access_token的有效性進行檢驗,并且每個一段時間會自動獲取一個新的access_token。
3. 處理微信消息的步驟
無論是事件推送還是消息推送,微信服務器都是以post的方式發送請求,推送的數據類型不是json而是xml,處理推送消息一般分為五個步驟:
3.1 接收xml數據
通過raw-body模塊可以獲取http模塊中的request對象,并且可以對數據進行拼裝,從而拿到一個buffer的xml對象
var data = yield rawBody(this.req,{        length:this.length,        limit:'1mb',        encoding:this.charset      });console.log('data:'+data);
3.2 解析xml數據
使用xml2js模塊,將xml數據解析成對象格式
var content = yield util.parseXMLAsync(data);util中的parseXMLAsync方法:exports.parseXMLAsync = function(xml){  return new Promise(function(resolve,reject){    xml2js.parseString(xml,{trim:true},function(err,content){      err ? reject(err) : resolve(content);    })  });}
3.3 格式化xml數據
從解析的xml數據來看,數據雖然已經呈現鍵值對的形式,但是其值是數組的形式,需要進行扁平化處理:
var message = util.formatMessage(content.xml);
其本質就是遍歷數組中的值,因為在多圖文的消息中存在嵌套的情況:
function formatMessage(result){  var message = {};  if(typeof result === 'object'){    var keys = Object.keys(result);    for(var i=0;i<keys.length;i++){      var key = keys[i];      var item = result[key];      if(!(item instanceof Array) || item.length === 0) continue;      if (item.length === 1){        var val = item[0];        if (typeof val === 'object') message[key] = formatMessage(val);        else message[key] = (val || '').trim();      }else{        message[key] = [];        for(var j=0,k=item.length;j<k;j++) message[key].push(formatMessage(item[j]));      }    }  }  return message;}
3.4 判斷消息類型并回復
這里針對subscribe事件,新關注后自動回復文本消息終于等到你,還好我沒放棄
if(message.MsgType === 'event'){  if(message.Event === 'subscribe'){    var createTime = new Date().getTime();    that.status = 200;    that.type = 'application/xml';    that.body = '<xml>'+          '<ToUserName><![CDATA['+ message.FromUserName +']]></ToUserName>'+          '<FromUserName><![CDATA['+ message.ToUserName +']]></FromUserName>'+          '<CreateTime>'+createTime+'</CreateTime>'+          '<MsgType><![CDATA[text]]></MsgType>'+          '<Content><![CDATA[終于等到你,還好我沒放棄]]></Content>'+          '</xml>'    return;  }}注:這里只是簡單地實現一下自動回復功能,這種拼接字符串的方式還是很不方便的,后面會封裝成接口。
使用手機微信掃描測試賬號的二維碼,即可關注,同時接收到測試公眾號推送的消息!

啦啦,一個簡單的關注回復就完成了。
以上就是本文的全部內容,希望對大家的學習有所幫助,也希望大家多多支持武林網。
新聞熱點
疑難解答