为什么使用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 相关文章推荐
javascript获取网页中指定节点的父节点、子节点的方法小结
Apr 24 Javascript
JQuery对id中含有特殊字符的转义处理示例
Sep 06 Javascript
javascript间隔刷新的简单实例
Nov 14 Javascript
jquery ajax 局部无刷新更新数据的实现案例
Feb 08 Javascript
JavaScript函数学习总结以及相关的编程习惯指南
Nov 16 Javascript
JavaScript统计网站访问次数的实现代码
Nov 18 Javascript
jquery表格datatables实例解析 直接加载和延迟加载
Aug 12 Javascript
深入理解bootstrap框架之第二章整体架构
Oct 09 Javascript
读Javascript高性能编程重点笔记
Dec 21 Javascript
小程序清理本地缓存的方法
Aug 17 Javascript
Vue+elementui 实现复杂表头和动态增加列的二维表格功能
Sep 23 Javascript
JavaScript享元模式原理与用法实例详解
Mar 09 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
re0第二季蕾姆被制作组打入冷宫!艾米莉亚女主扶正,原因唏嘘
2020/04/02 日漫
PHP脚本的10个技巧(5)
2006/10/09 PHP
PHP新手用的Insert和Update语句构造类
2012/03/31 PHP
解析PHP中VC6 X86和VC9 X86的区别及 Non Thread Safe的意思
2013/06/28 PHP
PHP验证类的封装与使用方法详解
2019/01/10 PHP
比较简单实用的使用正则三种版本的js去空格处理方法
2007/11/18 Javascript
JavaScript高级程序设计 XML、Ajax 学习笔记
2011/09/10 Javascript
jquery获得option的值和对option进行操作
2013/12/13 Javascript
jquery 图片缩放拖动的简单实例
2014/01/08 Javascript
用js模拟struts2的多action调用示例
2014/05/19 Javascript
js数组如何添加json数据及js数组与json的区别
2015/10/27 Javascript
JavaScript运行过程中的“预编译阶段”和“执行阶段”
2015/12/16 Javascript
BootStrap制作导航条实例代码
2016/05/06 Javascript
Node.js实现兼容IE789的文件上传进度条
2016/09/02 Javascript
Bootstrap CSS组件之按钮下拉菜单
2016/12/17 Javascript
详解如何在NodeJS项目中优雅的使用ES6
2017/04/22 NodeJs
jQuery实现上传图片前预览效果功能
2017/08/03 jQuery
AngularJS路由删除#符号解决的办法
2017/09/28 Javascript
jquery根据name取得select选中的值实例(超简单)
2018/01/25 jQuery
JavaScript链式调用实例浅析
2018/12/19 Javascript
layui监听select变化,以及设置radio选中的方法
2019/09/24 Javascript
基于VUE的v-charts的曲线显示功能
2019/10/01 Javascript
JavaScript中break、continue和return的用法区别实例分析
2020/03/02 Javascript
vue实现简单图片上传
2020/06/30 Javascript
Python3访问并下载网页内容的方法
2015/07/28 Python
Django实现分页功能
2018/07/02 Python
Django ManyToManyField 跨越中间表查询的方法
2018/12/18 Python
Python中的None与 NULL(即空字符)的区别详解
2020/09/24 Python
如何将字串String转换成整数int
2015/02/21 面试题
应届生护士求职信
2013/11/01 职场文书
幼儿园义卖活动方案
2014/01/17 职场文书
遗产继承公证书
2014/04/09 职场文书
审计专业自荐信范文
2014/04/21 职场文书
融资合作协议书范本
2014/10/17 职场文书
大学生自荐材料范文
2014/12/30 职场文书
高中数学教学反思范文
2016/02/18 职场文书