為什么使用koa2搭建微信第三方公眾平臺(tái)的原因
在寫之前我想先說說koa,koa相比express,在執(zhí)行流程,以及組件方面優(yōu)秀的多,koa本身沒有提供過多的擴(kuò)展組建,但是它便捷的組建擴(kuò)展,可以讓你自由的發(fā)揮,可以想寫其他語言一樣并行執(zhí)行代碼,如果說promise解放了繁瑣的callback,那么 koa 編寫 web 應(yīng)用,通過組合不同的 generator,可以免除重復(fù)繁瑣的回調(diào)函數(shù)嵌套,并極大地提升錯(cuò)誤處理的效率。koa 不在內(nèi)核方法中綁定任何中間件,它僅僅提供了一個(gè)輕量優(yōu)雅的函數(shù)庫,使得編寫 Web 應(yīng)用變得得心應(yīng)手,nodejs的天生的異步處理流程,使得它很適合微信公眾號(hào)這種頻繁的消息互動(dòng),再加上pm2的多進(jìn)程管理,可以說已經(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)開源,詳情請(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':
//測試
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 || '第一輪紅包雨開始了,手快有,手慢無!',
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);
//測試專用
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;
以上就是本文的全部內(nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
相關(guān)文章
node.js實(shí)現(xiàn)簡單的壓縮/解壓縮功能示例
這篇文章主要介紹了node.js實(shí)現(xiàn)簡單的壓縮/解壓縮功能,結(jié)合實(shí)例形式分析了node.js實(shí)現(xiàn)本地文件與服務(wù)器端壓縮/解壓縮相關(guān)操作技巧,需要的朋友可以參考下2019-11-11
Node.js中JWT實(shí)現(xiàn)身份驗(yàn)證的詳細(xì)步驟
身份驗(yàn)證是Web開發(fā)的重要組成部分,JWT由于其簡單性,安全性和可擴(kuò)展性,已成為在Web應(yīng)用程序中實(shí)現(xiàn)身份驗(yàn)證的流行方法,在這篇文章中,我將指導(dǎo)你在Node.js應(yīng)用程序中使用MongoDB進(jìn)行數(shù)據(jù)存儲(chǔ)來實(shí)現(xiàn)JWT身份驗(yàn)證,需要的朋友可以參考下2024-12-12
node.js請(qǐng)求HTTPS報(bào)錯(cuò):UNABLE_TO_VERIFY_LEAF_SIGNATURE\的解決方法
最近在工作中遇到一個(gè)問題,node.js請(qǐng)求HTTPS時(shí)報(bào)錯(cuò):Error: UNABLE_TO_VERIFY_LEAF_SIGNATURE\,通過查找網(wǎng)上的一些資料找到了解決方法,現(xiàn)在總結(jié)下分享給大家,有需要的朋友們可以參考借鑒,下面來一起看看吧。2016-12-12
利用node.js爬取指定排名網(wǎng)站的JS引用庫詳解
最近在學(xué)習(xí)node.js爬蟲,由于 nodejs 強(qiáng)大的異步特性,讓我們可以輕松以異步高并發(fā)去爬取網(wǎng)站,下面這篇文章主要給大家介紹了關(guān)于利用node.js爬取指定排名網(wǎng)站的JS引用庫的相關(guān)資料,需要的朋友可以參考下。2017-07-07
nodejs抓取notion?emoji?svg資源的腳本示例
這篇文章主要為大家介紹了nodejs抓取notion?emoji?svg資源腳本實(shí)現(xiàn)示例,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-02-02
Node使用Puppeteer監(jiān)聽并打印網(wǎng)頁的接口請(qǐng)求
Puppeteer 是一個(gè) Node 庫,它提供了高級(jí)的 API 來通過 DevTools 協(xié)議控制 Chrome 或 Chromium,本文我們就來看看如何使用Puppeteer監(jiān)聽并打印網(wǎng)頁的接口請(qǐng)求吧2025-04-04
Windows下安裝Bun像Node或Deno的現(xiàn)代JS運(yùn)行時(shí)
這篇文章主要為大家介紹了一款像Node或Deno的現(xiàn)代JavaScript運(yùn)行時(shí)的bun在Windows下安裝過程詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-07-07

