lxq.link
postscategoriestoolsabout

集成微信 JS-SDK - 基于 node 实现

在微信中打开的 H5 ,可以调用微信提供的原生功能,如拍照 / 自定义分享等。要想调用这些功能,需要先集成微信JS-SDK。

微信官方文档

集成微信JS-SDK有两个前置条件:

  1. 注册好的微信公众号。不同的公众号类型,获取的权限也不同,具体可以点这里查看

  2. 域名已备案


公众号后台配置

设置JS接口安全域名

进入公众号后台 => 公共号设置 => 功能设置 => JS接口安全域名设置

根据校验规则,以校验文件名为路径,将校验文件内容返回即可;

添加IP白名单

进入公众号后台 => 基本配置 => IP白名单

将服务器IP添加至IP白名单(调用access_token需要)


通过文档可以查看到,H5集成微信JS-SDK,在引入JS文件后,需要注入权限验证配置才能使用;

appId 在公众号后台 可以查看到,timestamp / nonceStr 这两个参数都是在生成 signature (签名)时自己设置的。

生成签名需要用到 jsapi_ticket

而生成jsapi_ticket又需要用到access_token;

具体签名算法和注意事项在文档有详细说明,这里看一下node的具体实现:

const axios = require ('axios');

// 定义一个全局字典
// 缓存 access_token 和 jsapi_ticket
let wxTokenObj = {};

// AppID(开发者ID)和AppSecret(开发者密码)在公众号后台查看
const AppID = '';
const AppSecret = '';

const updateAccessToken = async () => {
  // 获取 access_token
  const url = `https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=${AppID}&secret=${AppSecret}`;
  let res = await axios.get (url);

  if (!!res && !!res.data && !!res.data.access_token) {
    let accessToken = res.data.access_token;

    // 根据 access_token 获取 jsapi_ticket
    let jsapi_ticket_res = await axios.get (
      `https://api.weixin.qq.com/cgi-bin/ticket/getticket?access_token=${accessToken}&type=jsapi`
    );
    if (
      !!jsapi_ticket_res &&
      !!jsapi_ticket_res.data &&
      !!jsapi_ticket_res.data.ticket
    ) {
      // 缓存
      wxTokenObj.accessToken = accessToken;
      wxTokenObj.jsApiTicket = jsapi_ticket_res.data.ticket;
      wxTokenObj.expiresAt = res.data.expires_in;

      console.log(wxTokenObj);
    } else {
      await updateAccessToken ();
    }
  } else {
    await updateAccessToken ();
  }
};

const asyncToken = async () => {
  if (
    !wxTokenObj ||
    !wxTokenObj.expiresAt ||
    ((wxTokenObj.expiresAt - new Date()) < 30 * 60 * 1000)
  ) {
    await updateAccessToken ();
  }
};

(() => {
  asyncToken ();

  setInterval (async () => {
    try {
      await asyncToken ();
    } catch (e) {
      console.error ('async token error');
      console.error (e);
    }
  }, 10 * 60 * 1000);
}) ();

拿到 jsapi_ticket 后就可以生成配置JS-SDK需要的签名了,在上面的代码基础上添加一个node服务:

const {parse} = require ('url');
const crypto = require ('crypto');

function sha1 (str) {
  let shasum = crypto.createHash ('sha1');
  return shasum.update (str, 'utf-8').digest ('hex');
}

// 创建一个node server
let server = https.createServer (options, (req, res) => {
  const parsedUrl = parse (req.url, true);
  const {pathname} = parsedUrl;

  if (pathname === '/wx_signature') {
    try {
      let nonceStr = Math.floor (Math.random () * 10000).toString ();
      let timestamp = Math.floor (+new Date () / 1000);

      // 签名用的url必须是调用JS接口页面的完整URL
      let url = req.headers.referer;

      // 使用缓存的 jsApiTicket
      let jsApiTicket = wxTokenObj.jsApiTicket;
      let str = `jsapi_ticket=${jsApiTicket}&noncestr=${nonceStr}&timestamp=${timestamp}&url=${url}`;
      let signature = sha1 (str);
      res.end (
        JSON.stringify ({appId: AppID, nonceStr, timestamp, signature, url})
      );
    } catch (e) {
      console.log (e);
      res.end ('error');
    }
  }
});

server.listen (8000);

微信 JS 接口签名校验工具

2020-05-31