为什么使用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 相关文章推荐
通过JS自动隐藏手机浏览器的地址栏实现原理与代码
Jan 02 Javascript
js 走马灯简单实例
Nov 21 Javascript
JS实现完全语义化的网页选项卡效果代码
Sep 15 Javascript
理解javascript函数式编程中的闭包(closure)
Mar 08 Javascript
返回函数的JavaScript函数
Jun 14 Javascript
js中通过getElementsByName访问name集合对象的方法
Oct 31 Javascript
浅谈在fetch方法中添加header后遇到的预检请求问题
Aug 31 Javascript
基于JavaScript实现幸运抽奖页面
Jul 05 Javascript
vue+axios+mock.js环境搭建的方法步骤
Aug 28 Javascript
Angular中innerHTML标签的样式不起作用的原因解析
Jun 18 Javascript
vue页面切换项目实现转场动画的方法
Nov 12 Javascript
vue element自定义表单验证请求后端接口验证
Dec 11 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
外媒评选出10支2020年最受欢迎的Dota2战队
2021/03/05 DOTA
关于UEditor编辑器远程图片上传失败的解决办法
2012/08/31 PHP
PHP中::、->、self、$this几种操作符的区别介绍
2013/04/24 PHP
php实现水仙花数示例分享
2014/04/03 PHP
php注册和登录界面的实现案例(推荐)
2016/10/24 PHP
PHP实现登陆表单提交CSRF及验证码
2017/01/24 PHP
拖动一个HTML元素
2006/12/22 Javascript
jQuery select控制插件
2009/08/17 Javascript
Jquery公告滚动+AJAX后台得到数据
2011/04/14 Javascript
brook javascript框架介绍
2011/10/10 Javascript
Jquery 改变radio/checkbox选中状态,获取选中的值(示例代码)
2013/12/12 Javascript
浅谈javascript 函数表达式和函数声明的区别
2016/01/05 Javascript
通过jsonp获取json数据实现AJAX跨域请求
2017/01/22 Javascript
原生js编写2048小游戏
2017/03/17 Javascript
纯js代码生成可搜索选择下拉列表的实例
2018/01/11 Javascript
超好用的jQuery分页插件jpaginate用法示例【附源码下载】
2018/12/06 jQuery
express 项目分层实践详解
2018/12/10 Javascript
js模拟F11页面全屏显示
2019/09/17 Javascript
JavaScript面向对象核心知识与概念归纳整理
2020/05/09 Javascript
[09:43]DOTA2每周TOP10 精彩击杀集锦vol.5
2014/06/25 DOTA
[38:40]2018DOTA2亚洲邀请赛 4.6淘汰赛 mineski vs LGD 第一场
2018/04/10 DOTA
Python动态加载模块的3种方法
2014/11/22 Python
通过C++学习Python
2015/01/20 Python
通过python改变图片特定区域的颜色详解
2019/07/15 Python
解决Django 在ForeignKey中出现 non-nullable field错误的问题
2019/08/06 Python
windows环境中利用celery实现简单任务队列过程解析
2019/11/29 Python
Python写出新冠状病毒确诊人数地图的方法
2020/02/12 Python
django模型类中,null=True,blank=True用法说明
2020/07/09 Python
Python局部变量与全局变量区别原理解析
2020/07/14 Python
python中plt.imshow与cv2.imshow显示颜色问题
2020/07/16 Python
python爬虫beautifulsoup解析html方法
2020/12/07 Python
Python爬虫进阶之爬取某视频并下载的实现
2020/12/08 Python
你们项目是如何进行变更控制的
2015/08/26 面试题
应届生船舶驾驶求职信
2013/10/19 职场文书
党员干部作风建设思想汇报范文
2014/10/25 职场文书
文员岗位职责范本
2015/04/16 职场文书