为什么使用koa2搭建微信第三方公众平台的原因


Posted in Javascript onMay 16, 2018

在写之前我想先说说koa,koa相比express,在执行流程,以及组件方面优秀的多,koa本身没有提供过多的扩展组建,但是它便捷的组建扩展,可以让你自由的发挥,可以想写其他语言一样并行执行代码,如果说promise解放了繁琐的callback,那么 koa 编写 web 应用,通过组合不同的 generator,可以免除重复繁琐的回调函数嵌套,并极大地提升错误处理的效率。koa 不在内核方法中绑定任何中间件,它仅仅提供了一个轻量优雅的函数库,使得编写 Web 应用变得得心应手,nodejs的天生的异步处理流程,使得它很适合微信公众号这种频繁的消息互动,再加上pm2的多进程管理,可以说已经很大程度的满足大号的消息转发互动已经公众号内部红包玩法。

在使用koa2搭建微信第三方公众平台是,首先要解决的是如果获取微信返回的xml流,以及如何返回对应的XML体给微信。
由于本身koa不是一个框架,所以得益于网上众多的中间件,自己搭建了一个类似于express的框架,本框架已经开源,详情请看我的git地址:https://github.com/yxz1025/koa-lana,所有的微信接发消息均在此框架中,请读者自行下载!

好了,首先,我们看看如何获取微信返回的xml流:

======tool.js=====
//截获微信返回的xml流文件
const Promise = require('bluebird');
//普通post流转化为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======
//微信响应主体文件
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);

//第三方授权路径 /: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!'; // 指纹码不匹配时返回错误信息,禁止后面的消息接受及发送
  }
  let message = middleware.decryptXml(xml);
  let appid = ctx.params.appid;
  message.appId = appid;
  //发送消息队列
  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 || '点我领红包',
          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);

        //获取授权域名
        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;

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持三水点靠木。

Javascript 相关文章推荐
使用SyntaxHighlighter实现HTML高亮显示代码的方法
Feb 04 Javascript
jquery ui对话框实例代码
May 10 Javascript
JavaScript实现带缓冲效果的随屏滚动漂浮广告代码
Nov 06 Javascript
深入理解JS中的substr和substring
Apr 26 Javascript
JavaScript判断用户名和密码不能为空的实现代码
May 16 Javascript
JS实现兼容火狐及IE iframe onload属性的遮罩层隐藏及显示效果
Aug 23 Javascript
Vue.js每天必学之数据双向绑定
Sep 05 Javascript
js拼接html字符串的注意事项
Oct 13 Javascript
jQuery滚动监听实现商城楼梯式导航效果
Mar 06 Javascript
利用js编写网页进度条效果
Oct 08 Javascript
jquery获取元素到屏幕四周可视距离的方法
Sep 05 jQuery
Electron整合React使用搭建开发环境的步骤详解
Jun 07 Javascript
详解基于Koa2开发微信二维码扫码支付相关流程
May 16 #Javascript
AngularJS标签页tab选项卡切换功能经典实例详解
May 16 #Javascript
解决Mac node版本升级失败的问题
May 16 #Javascript
在Mac下彻底卸载node和npm的方法
May 16 #Javascript
完美解决linux下node.js全局模块找不到的情况
May 16 #Javascript
AngularJS中的作用域实例分析
May 16 #Javascript
element-ui 限制日期选择的方法(datepicker)
May 16 #Javascript
You might like
冰滴咖啡制作步骤
2021/03/03 冲泡冲煮
php中禁止单个IP与ip段访问的代码小结
2012/07/04 PHP
使用php+apc实现上传进度条且在IE7下不显示的问题解决方法
2013/04/25 PHP
php设计模式之简单工厂模式详解
2014/09/04 PHP
如何让PHP编码更加好看利于阅读
2019/05/12 PHP
php 使用 __call实现重载功能示例
2019/11/18 PHP
showModelessDialog()使用详解
2006/09/21 Javascript
JavaScript 用Node.js写Shell脚本[译]
2012/09/20 Javascript
JavaScript中的连字符详解
2013/11/28 Javascript
解析JavaScript中instanceof对于不同的构造器或许都返回true
2013/12/03 Javascript
NodeJS使用jQuery选择器操作DOM
2015/02/13 NodeJs
AngularJS基础知识笔记之表格
2015/05/10 Javascript
js实现简单计算器
2015/11/22 Javascript
基于jQuery实现点击弹出层实例代码
2016/01/01 Javascript
JavaScript中removeChild 方法开发示例代码
2016/08/15 Javascript
jQuery 如何实现一个滑动按钮开关
2016/12/01 Javascript
ES6新特性六:promise对象实例详解
2017/04/21 Javascript
javascript数组拍平方法总结
2018/01/20 Javascript
微信小程序实现手指触摸画板
2018/07/09 Javascript
Vue简单封装axios之解决post请求后端接收不到参数问题
2020/02/16 Javascript
解决vue数据不实时更新的问题(数据更改了,但数据不实时更新)
2020/10/27 Javascript
[01:16:50]DOTA2-DPC中国联赛 正赛 Phoenix vs CDEC BO3 第一场 3月7日
2021/03/11 DOTA
Python实现树的先序、中序、后序排序算法示例
2017/06/23 Python
Python 静态方法和类方法实例分析
2019/11/21 Python
PyCharm使用Docker镜像搭建Python开发环境
2019/12/26 Python
Tensorflow设置显存自适应,显存比例的操作
2020/02/03 Python
django 链接多个数据库 并使用原生sql实现
2020/03/28 Python
python 操作mysql数据中fetchone()和fetchall()方式
2020/05/15 Python
Zavvi荷兰:英国大型音像制品和图书游戏零售商
2018/03/22 全球购物
巴西一家专门从事家居和装饰的连锁店:Camicado
2019/08/14 全球购物
如果一个类实现了多个接口但是这些接口有相同的方法名将会怎样
2013/06/16 面试题
《假如》教学反思
2014/04/17 职场文书
通知函格式范文
2015/04/27 职场文书
《窃读记》教学反思
2016/02/18 职场文书
如何使用Python对NetCDF数据做空间相关分析
2021/04/21 Python
关于 Python json中load和loads区别
2021/11/07 Python