微信公众号

275 阅读3分钟

准备

  • sunny-ngrok工具安装及注册账号(国内建的私服)
    1. 什么叫做内网穿透
      • 内网下可以调别人,别人连接自己是不行的,因为没有公网ip,所以需要公网ip地址
  • 模拟公网IP端口方法
    1. 申请一台阿里云ECS
    2. 公司网络有一个公网IP 路由器端口映射
    3. ngrok 内网穿透 国际版本(二级域名,每次启动都不一样)

客服消息

开发者工具 -> 公众平台测试账号 ,微信认证 验证成功,就会继续往下走。

  • 我们验证微信,认证很重要 ,再有签名算法也是这样完成的,SHA1加密()

    • hash算法不可逆
    • 消息摘要,雪崩效应
    • 防止第三方劫持盗取服务器信息
    • 防止资源被诱导走,或者发送不健康的请求
    const url = require('url') //引入url包
    const {
        query
    } = url.parse(ctx.url, true)
    const {
      signature, // 微信加密签名,signature结合了开发者填写的token参数和请求中的		   timestamp参数、nonce参数。
      timestamp, // 时间戳
      nonce, // 随机数 
      echostr // 随机字符串
    } = query
    
     // 将 token timestamp nonce 三个参数进行字典序排序并用sha1加密
    对比签名  加密规则是已知的
    let str = [conf.token, timestamp, nonce].sort().join('');
    let strSha1 = crypto.createHash('sha1').update(str).digest('hex');
    console.log(`自己加密后的字符串为:${strSha1}`);
    console.log(`微信传入的加密字符串为:${signature}`);
    console.log(`两者比较结果为:${signature == strSha1}`);
    
  • 设置一个密钥,是以某种方式设置到服务器端,让双方知晓,对方发请求时会给发一次签名,签名算法是公开,但是对方知道是利用密钥产生的,加密密文是随机数。验证对方是否拥有token,只有拥有token才可以产生签名。再次签名,如果签名正确,则判断是token的使用者并且是合法用户。(很多地方会用到这种设计)

  • 微信请求(源码接收部分)

    • 接收时 (报文body xml格式)
    • 发送要发送 xml
    • const xml2js = require('xml2js') xml和json两者转换
    const {
        xml: msg   // 接收xml
    } = ctx.request.body
    const builder = new xml2js.Builder()
    const result = builder.buildObject({
        xml: {    // 返回xml
            ToUserName: msg.FromUserName,
            FromUserName: msg.ToUserName,
            CreateTime: Date.now(),
            MsgType: msg.MsgType,
            Content: 'Hello ' + msg.Content
        }
    })
    

服务端API调用 (菜单的工作变成程序的实现)

  • 不需要ngroke,调用服务器接口不要
  • 不是restful接口,微信官方定义风格,链接最后是get
  • 获取的用户id,叫opneId,保证在同一个公众号统一的,在不同的不一样,要想保证一样,要注册,会有unionid,unionid可以保证在多个公众号一致。
  • 第一步要 获取access_token 才可以使用其他API
    https请求方式: GET https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=APPID&secret=APPSECRET
    
  • AOP切面编程 intercpter,拦截器
    • 微信公共平台API
    const WechatAPI = require('co-wechat-api');
    const api = new WechatAPI(conf.appid, conf.appsecret) // 创建实例
    //微信API所有方法都有封装
    api.getFollowers();
    
    • co-wechat-api
    1. promise风格
    2. mixin方法,内部自己写了个mixin方法
    const API = require('./lib/api_common');
    // 菜单接口
    API.mixin(require('./lib/api_menu'));
    /**
     * 用于支持对象合并。将对象合并到API.prototype上,使得能够支持扩展
     * Examples:
     * ```
     * // 媒体管理(上传、下载)
     * API.mixin(require('./lib/api_media'));
     * ```
     * @param {Object} obj 要合并的对象
     */
    API.mixin = function (obj) {
      for (var key in obj) {
        if (API.prototype.hasOwnProperty(key)) {
          throw new Error('Don\'t allow override existed prototype method. method: '+ key);
        }
        API.prototype[key] = obj[key];
      }
    };
    
  • token要放起来,mongodb或者redias(key-value存储系统)里面
    const { ServerToken} = require('./mongoose')
    const api = new WechatAPI(
        conf.appid, 
        conf.appsecret,
        async function () {  // 取token
            return await ServerToken.findOne()
        },
        async function (token) {  // 存token
                const res = await ServerToken.updateOne({}, token, { upsert: 			true })
        }
    
    );
    
  • 标准restful接口,github,es
  • graphql格式
  • 测试驱动开发(TDD Test Driver Development)
  • 官方文
  • npm库
  • co-wechat-api文档
  • co-wechat-api源码地址