Part 1. 驗(yàn)證公眾號 (開發(fā)者)
- 名詞解釋
- timestamp 時間戳
- nonce 隨機(jī)數(shù)
- token+timestamp+nonce
- signature 簽名
- 驗(yàn)證順序
- 上面三者排序
- 拼接后利用sha1模塊進(jìn)行加密
- 與signature進(jìn)行對比
相等就表示來源于微信,返回echostr
Part 2. acess_token獲取與儲存
- 當(dāng)普通微信用戶向公眾賬號發(fā)消息時,微信服務(wù)器將POST消息的XML數(shù)據(jù)包到開發(fā)者填寫的URL上。
- 名詞解釋
- acess_token :憑據(jù),有效期2h,沒兩個小時就要重新獲?。ǐ@取完上一個失效)一種憑證,而且要保證他只在唯一位置,不然會發(fā)生沖突官方解釋
- 設(shè)計思路
- 創(chuàng)建構(gòu)造函數(shù),有請求方的appID、appSecret屬性以及對acess_token進(jìn)行操作的兩個方法getAccessToken、saveAccessToken
- 在其原型上還定義了兩個方法isVaildAccessToken、updateAccessToken,分別用來識別憑證的有效性、若失效或者沒有憑證則重新發(fā)送請求進(jìn)行acess_token更新
- 創(chuàng)建了一個txt文件來儲存acess_token(使用了fs模塊:讀取寫入文件),文件寫入和讀取功能可以單獨(dú)儲存在一個公共方法util.js中,配置文檔路徑(path模塊)
Part 3. 回復(fù)測試
- 流程
- 接收請求以及對請求信息的處理
接收的請求使用getRawBody模塊來進(jìn)行處理,可以拼裝成一個bufferde的xml數(shù)據(jù),其參數(shù)是請求對象,對應(yīng)也就是ctx.req。
因?yàn)楂@取的是一個xml數(shù)據(jù),要對xml轉(zhuǎn)化成js,使用了xml2js模塊,然后獲取的xml對象中是數(shù)組形式,要重新遍歷,將其元素剖析出來,所以編寫了一個formatMessage的方法,分別判斷屬性值是否存在或類型是否為對象,然后遍歷到新的對象,這個方法有點(diǎn)像寫原生對象深復(fù)制,最后返回一個完整的對象數(shù)據(jù)message。
- 返回數(shù)據(jù)到用戶
- 判斷請求方法是'GET'還是'POST',當(dāng)請求方法也就是message.MsgType為‘GET’,我們可以通過判斷message.Event類型,來響應(yīng)用戶端的具體操作
- e.g(subscribe訂閱事件) 當(dāng)message.Event 為 'subscribe' 是用戶進(jìn)行了訂閱操作,我們通過書寫響應(yīng)體來進(jìn)行該請求的響應(yīng),返回的數(shù)據(jù)類型是ctx.type = 'application/xml',以及返回成功狀態(tài) ctx.status = 200,還有響應(yīng)的內(nèi)容要依據(jù)官方給定文檔格式返回,ctx.body = 官方特定格式
- e.g(返回文本消息)其格式為
ctx.body = '<xml>' +
'<ToUserName><![CDATA[' + message.FromUserName + ']]></ToUserName>' +
'<FromUserName><![CDATA[' + message.ToUserName +']]></FromUserName>' +
'<CreateTime>' + now + '</CreateTime>' +
'<MsgType><![CDATA[text]]></MsgType>' +
'<Content><![CDATA[歡迎關(guān)注Chan的微信公眾號]]></Content>' +
'</xml>'
// FromUserName 接收方
// ToUserName 發(fā)送方
// CreateTime 時間戳
// MsgType 消息類型
// Content 消息數(shù)據(jù)
Part 4. 消息處理
- 模板書寫
模板書寫的是返回格式,返回的格式是微信定好的,可以在官方文檔中查詢,主要區(qū)別是在回復(fù)類型的不同,回復(fù)的格式也不同。通過變量msgType(返回數(shù)據(jù)類型)來編譯模板進(jìn)行輸出,因?yàn)榉祷氐氖亲址唇?,所以使用了heredoc模塊(書寫)以及ejs模塊(編譯)來對應(yīng)數(shù)據(jù)類型的輸出 - 定制業(yè)務(wù)回復(fù)數(shù)據(jù)
回復(fù)格式的模板寫好了,我們可以定義回復(fù)內(nèi)容,并返回回復(fù)內(nèi)容等待下一步輸出,依據(jù)回復(fù)格式,回復(fù)文本則只需要設(shè)置content變量,而視頻或文章等需要定義多個變量,所以創(chuàng)建一個新的模塊來定制回復(fù)內(nèi)容的業(yè)務(wù)處理。- 因?yàn)槭褂胟oa所以該步驟通過await調(diào)用并獲取微信服務(wù)器返回并處理過的message數(shù)據(jù)。依據(jù)用戶提供的信息設(shè)置回復(fù)內(nèi)容content,最終返回需要回復(fù)的content,并調(diào)用next,執(zhí)行下一步代碼
- 此時app已經(jīng)獲得了content,需要通過第一步制作的模板編譯后保存到ctx.body,然后設(shè)置status, type。對微信服務(wù)器發(fā)送請求,等待服務(wù)器對用戶進(jìn)行信息回復(fù)。
Part 5. 微信SDK應(yīng)用
- 配置
- 綁定域名 (備案,一級以上)
- 引入JS文件 (直接添加一個html頁面到一個中間件中:可以不用路由 )
- JS SDK的初始化 -- 使得內(nèi)置網(wǎng)頁可以調(diào)用微信原生應(yīng)用(掃一掃,搖一搖,拍照,語音等)
依賴
koa 框架 類似express框架 --回調(diào)中間件應(yīng)用
sha1 --加密模塊
request --請求封裝模塊 --請求使用
bluebird --node上的實(shí)現(xiàn)Pormise的模塊,而且還可以讓request模塊promisify化
raw-body --解析請求還能限制其數(shù)據(jù)內(nèi)容或格式
xml2js --將xml數(shù)據(jù)格式轉(zhuǎn)化成js對象
heredoc --創(chuàng)建多行字符串
ejs --可以在編譯模板中使用了<% %>的代碼,使得在字符創(chuàng)中可以直接使用JS代碼
ES6知識須知
- generator 生成器(可以使得函數(shù)在哪一步進(jìn)行暫?;蚶^續(xù)執(zhí)行等) generator,配合yield方法來確定回調(diào)順序
- Promise ----> 使得回調(diào)更好的維護(hù),更清晰,將回調(diào)的函數(shù)單獨(dú)抽離出來分別用
.then(成功執(zhí)行)
.catch(錯誤執(zhí)行)
node blurbird模塊實(shí)現(xiàn)了原生promise的方法
new Promise((resolve, reject) => {}) // 使用方法
成功使用resolve返回,失敗使用reject返回
問題
- koa運(yùn)行時警告
koa deprecated Support for generators will be removed in v3
使用新的寫法即可,參考
https://github.com/koajs/koa/
注意使用了koa2以上的版本后響應(yīng)和請求對象不再this,而是在一開始設(shè)置的ctx參數(shù)中了。之前一般this獲取的方法或?qū)傩垣@取不到注意下是不是ctx有關(guān)。 - request發(fā)送請求后返回的data在響應(yīng)對象responce的body屬性中
.then(res=>{console.log(res.body)}) ===>request promisify化 - 當(dāng)和微信公眾號平臺進(jìn)行連接時,提示了token check fail 但是返回的數(shù)據(jù)又相等,可能是域名填寫的問題(我是用的是云服務(wù)器給的公網(wǎng)IP解析了一個域名,域名沒備案不讓使用,所以能接受但用不了,可以直接用IP連接)
- Koa中間件的數(shù)據(jù)傳遞,可以將數(shù)據(jù)儲存在ctx.state,亦或是使用call方法將執(zhí)行上下文改為ctx,來獲取數(shù)據(jù)。
// app.js
ctx.state.msg = message // 把解析好的message儲存 koa的特有方法就是存在state中
await handler(ctx, next) // 讓業(yè)務(wù)處理儲存好的message
// handler.js
var message = ctx.state.msg // 來獲取儲存的數(shù)據(jù)
reply.call(ctx) // 處理完后調(diào)用回復(fù)的方法
// reply.js
var body = this.body // this.body ,因?yàn)榻壎薱tx ===> 和在app中調(diào)用 ctx.body一樣
- 在上傳臨時素材并設(shè)置公眾號返回信息時,若文件比較大上傳時間長,微信服務(wù)器等待響應(yīng)超過5s則不會返回視頻,并且會重復(fù)3次請求,這樣就進(jìn)行了3次上傳,一般情況下不建議自動回復(fù)臨時上傳的視頻,而是直接調(diào)用上傳后的素材后微信服務(wù)器返回的media_id
- 有時候會提示.then 未定義,是因?yàn)榍懊娴拇a有的沒有返回Promise對象,多以導(dǎo)致使用不了then的方法。
- 有關(guān)相機(jī)相冊、地理位置的信息事件信息,微信服務(wù)器會先返回一個當(dāng)前事件的事件信息,然后在返回一個普通消息(照片對應(yīng)回復(fù)照片信息,地理位置對應(yīng)地理位置)掃描二維碼只返回一個事件消息。
- koa中中間件傳遞POST數(shù)據(jù)時記得next(ctx),要將ctx傳遞下去否則會發(fā)生FORM數(shù)據(jù)錯誤