為什么使用koa2搭建微信第三方公眾平臺(tái)的原因
在寫(xiě)之前我想先說(shuō)說(shuō)koa,koa相比express,在執(zhí)行流程,以及組件方面優(yōu)秀的多,koa本身沒(méi)有提供過(guò)多的擴(kuò)展組建,但是它便捷的組建擴(kuò)展,可以讓你自由的發(fā)揮,可以想寫(xiě)其他語(yǔ)言一樣并行執(zhí)行代碼,如果說(shuō)promise解放了繁瑣的callback,那么 koa 編寫(xiě) web 應(yīng)用,通過(guò)組合不同的 generator,可以免除重復(fù)繁瑣的回調(diào)函數(shù)嵌套,并極大地提升錯(cuò)誤處理的效率。koa 不在內(nèi)核方法中綁定任何中間件,它僅僅提供了一個(gè)輕量?jī)?yōu)雅的函數(shù)庫(kù),使得編寫(xiě) Web 應(yīng)用變得得心應(yīng)手,nodejs的天生的異步處理流程,使得它很適合微信公眾號(hào)這種頻繁的消息互動(dòng),再加上pm2的多進(jìn)程管理,可以說(shuō)已經(jīng)很大程度的滿足大號(hào)的消息轉(zhuǎn)發(fā)互動(dòng)已經(jīng)公眾號(hào)內(nèi)部紅包玩法。
在使用koa2搭建微信第三方公眾平臺(tái)是,首先要解決的是如果獲取微信返回的xml流,以及如何返回對(duì)應(yīng)的XML體給微信。
由于本身koa不是一個(gè)框架,所以得益于網(wǎng)上眾多的中間件,自己搭建了一個(gè)類似于express的框架,本框架已經(jīng)開(kāi)源,詳情請(qǐng)看我的git地址:https://github.com/yxz1025/koa-lana,所有的微信接發(fā)消息均在此框架中,請(qǐng)讀者自行下載!
好了,首先,我們看看如何獲取微信返回的xml流:
======tool.js===== //截獲微信返回的xml流文件 const Promise = require('bluebird'); //普通post流轉(zhuǎn)化為promise var Tool = { convertPost: function(req) { let post_data = ""; return new Promise(function(resolve, reject){ req.on('data', function(chunk) { post_data += chunk; }); req.on('end', function() { resolve(post_data); }); }); }, }; module.exports = Tool; =====weichat.js====== //微信響應(yīng)主體文件 const router = require('koa-router')(); const parseMessage = require('../common/parseMessage'); const config = require('../config'); const WXBizMsgCrypt = require('wechat-crypto'); const middleware = require('../model/middleware'); const validator = require('validator'); const Aes = require('../common/aes'); const Tool = require('../common/tool'); const cryptor = new WXBizMsgCrypt(config.component_config.token, config.component_config.key, config.component_config.component_appid); //第三方授權(quán)路徑 /:appid/callback /wechat/100234/callback router.post('/:appid/callback', async function(ctx, next) { let post_data = ""; let req = ctx.req; post_data = await Tool.convertPost(req); let xml = parseMessage(post_data); let signature = cryptor.getSignature(ctx.query.timestamp, ctx.query.nonce, xml.encrypt); if (ctx.query.msg_signature != signature) { ctx.body = 'Auth failed!'; // 指紋碼不匹配時(shí)返回錯(cuò)誤信息,禁止后面的消息接受及發(fā)送 } let message = middleware.decryptXml(xml); let appid = ctx.params.appid; message.appId = appid; //發(fā)送消息隊(duì)列 switch (message.msgType) { case 'text': //測(cè)試 if (message.toUserName == "gh_3c884a361561") { if (message.content == "TESTCOMPONENT_MSG_TYPE_TEXT") { let text = middleware.text(message, message.content + "_callback"); let reply = middleware.encryptXml(text); return ctx.body = reply; } let content = message.content; if (content.indexOf("QUERY_AUTH_CODE") != -1) { ctx.body = ""; let code_li = content.split(":"); await middleware.customSend(message.fromUserName, code_li[1]); return; } } let keywords = validator.trim(message.content).toLowerCase(); let member_config = await middleware.getMemberConfig(message.toUserName, keywords); if (!member_config) { await middleware.sendMnsQuene(message); return ctx.body = "success"; }else{ //匹配成功 message.packetsId = parseInt(member_config.hongbaoId); message.keywords = keywords; await middleware.sendMnsQuene(message); let data = { title: member_config.news_title || '點(diǎn)我領(lǐng)紅包', description: member_config.description || '第一輪紅包雨開(kāi)始了,手快有,手慢無(wú)!', picurl: member_config.picurl || 'http://7xqomp.com2.z0.glb.qiniucdn.com/17269743.png' }; let key = { fromUserName: message.fromUserName, toUserName: message.toUserName, keywords: keywords, appId: appid }; key = JSON.stringify(key); key = Aes.encypt(key); key = Aes.base64_encode(key); //獲取授權(quán)域名 let auth_url = await middleware.packetDomain(); data.url = "http://" + appid + "." + auth_url + "/redPackets/koulin?key=" + key; let news = middleware.news(message, [data]); let reply = middleware.encryptXml(news); ctx.body = reply; return; } break; case 'event': await middleware.sendMnsQuene(message); //測(cè)試專用 if (message.toUserName == "gh_3c884a361561") { let text = middleware.text(message, message.event + "from_callback"); let reply = middleware.encryptXml(text); ctx.body = reply; return; } break; default: await middleware.sendMnsQuene(message); ctx.body = "success"; return; }; }); module.exports = router;
以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
相關(guān)文章
Node.js中使用Log.io在瀏覽器中實(shí)時(shí)監(jiān)控日志(等同tail -f命令)
這篇文章主要介紹了Node.js中使用Log.io在瀏覽器中實(shí)時(shí)監(jiān)控日志,Log.io等同于tail -f命令,但更強(qiáng)大,需要的朋友可以參考下2014-09-09nodejs結(jié)合Socket.IO實(shí)現(xiàn)的即時(shí)通訊功能詳解
這篇文章主要介紹了nodejs結(jié)合Socket.IO實(shí)現(xiàn)的即時(shí)通訊功能,結(jié)合實(shí)例形式詳細(xì)分析了nodejs結(jié)合Socket.IO實(shí)現(xiàn)即時(shí)通訊的相關(guān)操作技巧與注意事項(xiàng),需要的朋友可以參考下2018-01-01基于nodejs+express(4.x+)實(shí)現(xiàn)文件上傳功能
通過(guò)一段時(shí)間的查閱資料發(fā)現(xiàn)實(shí)現(xiàn)上傳的方式有:1.express中間件multer模塊2.connect-multiparty模塊(但現(xiàn)在 官方不推薦 )3.使用multiparty模塊實(shí)現(xiàn)4.使用formidable插件實(shí)現(xiàn),本文給大家介紹nodejs+express(4.x+)實(shí)現(xiàn)文件上傳功能,需要的朋友參考下2015-11-11express框架+bootstrap美化ejs模板實(shí)例分析
這篇文章主要介紹了express框架+bootstrap美化ejs模板,結(jié)合實(shí)例形式分析了express框架引入bootstrap結(jié)合ejs模版引擎相關(guān)操作技巧與注意事項(xiàng),需要的朋友可以參考下2023-05-05nodejs 實(shí)現(xiàn)MQTT協(xié)議的服務(wù)器端和客戶端的雙向交互的過(guò)程
這篇文章主要介紹了nodejs 實(shí)現(xiàn)MQTT協(xié)議的服務(wù)器端和客戶端的雙向交互的過(guò)程,本文通過(guò)示例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友參考下吧2023-11-11node.js調(diào)用Chrome瀏覽器打開(kāi)鏈接地址的方法
其實(shí)在Node.JS中打開(kāi)瀏覽器網(wǎng)址非常簡(jiǎn)單,但還是有必要整理下分享給有需要的朋友們,這篇文章主要給大家介紹了node.js如何調(diào)用Chrome瀏覽器打開(kāi)鏈接地址的方法,文中介紹的非常詳細(xì),需要的朋友們下面隨著小編來(lái)一起看看吧。2017-05-05express搭建的nodejs項(xiàng)目使用webpack進(jìn)行壓縮打包
對(duì)于打包這個(gè)問(wèn)題它并不是難點(diǎn),但是對(duì)于我們這種初學(xué)者來(lái)說(shuō),根本就不知道應(yīng)該怎么做,下面這篇文章主要給大家介紹了關(guān)于express搭建的nodejs項(xiàng)目使用webpack進(jìn)行壓縮打包的相關(guān)資料,需要的朋友可以參考下2022-12-12Nodejs獲取網(wǎng)絡(luò)數(shù)據(jù)并生成Excel表格
這篇文章主要為大家詳細(xì)介紹了Nodejs獲取網(wǎng)絡(luò)數(shù)據(jù)并生成Excel表格的具體實(shí)現(xiàn)方法,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2016-05-05