记录使用微信公众号jssdk的坑

        最近工作中遇到了需要使用微信jssdk的场景,捣鼓了大半个礼拜,踩了很多坑,终于还是解决了,记录一下!

官方文档:https://developers.weixin.qq.com/doc/offiaccount/OA_Web_Apps/JS-SDK.html

一.绑定域名

在公众号平台上注册一个测试号,使用natapp进行内网穿透,并配置JS接口安全域名

二.获取access_token

        后台部分使用nodejs编写,access_token的有效期目前为2个小时。官方建议开发者使用中控服务器统一获取和刷新access_token,其他业务逻辑服务器所使用的access_token均来自于该中控服务器,不应该各自去刷新,否则容易造成冲突。即2小时内可以使用同一个access_token,不用多次请求,node部分代码如下:

// 定义刷新access_token的函数
function refreshAccessToken() {
    const tokenUrl = `https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=${AppID}&secret=${AppSecret}`;
    request.get(tokenUrl, function (err, res, body) {
        if (err) {
            console.error(err);
            return;
        }
        const accessToken = JSON.parse(body).access_token;
        // 更新全局变量中的accessToken
        global.access_token = accessToken;
        //更新accessToken后重新获取jsapiTicket
        refreshJsapiTicket()
        // 每隔REFRESH_INTERVAL时间间隔刷新一次access_token
        setInterval(refreshAccessToken, REFRESH_INTERVAL);
    });
}

三.获取jsapi_ticket

        和access_token一样,有效期为2个小时,通过access_token来获取。由于获取jsapi_ticket的api调用次数非常有限,频繁刷新jsapi_ticket会导致api调用受限,影响自身业务,开发者必须在自己的服务全局缓存jsapi_ticket 。node部分代码如下:

// 定义刷新jsapi_ticket的函数
function refreshJsapiTicket() {
    const ticketUrl = `https://api.weixin.qq.com/cgi-bin/ticket/getticket?access_token=${global.access_token}&type=jsapi`;
    request.get(ticketUrl, function (err, res, body) {
        if (err) {
            console.error(err);
            return;
        }
        console.log(JSON.parse(body))
        const jsapiTicket = JSON.parse(body).ticket;
        // 更新全局变量中的jsapiTicket
        global.jsapiTicket = jsapiTicket;
    });
}

四.url部分

        这也是最容易踩坑的地方。按照官方说法,前台按照encodeURIComponent(window.location.href.split('#')[0])传给后台即可,需要注意的是。前台进行了编码,后台一定要对url进行解码,否则会失败。

let url = decodeURIComponent(req.body.url)

五.signature

        直接按照官方给的demo,获取nonceStr,timestamp,最后把jsapi_ticket和url组合一下,进行加密,代码如下:

var createNonceStr = function () {
  return Math.random().toString(36).substring(2, 15);
};

var createTimestamp = function () {
  return parseInt(new Date().getTime() / 1000) + '';
};

var raw = function (args) {
  var keys = Object.keys(args);
  keys = keys.sort()
  var newArgs = {};
  keys.forEach(function (key) {
    newArgs[key.toLowerCase()] = args[key];
  });

  var string = '';
  for (var k in newArgs) {
    string += '&' + k + '=' + newArgs[k];
  }
  string = string.substr(1);
  return string;
};

/**
* @synopsis 签名算法 
*
* @param jsapi_ticket 用于签名的 jsapi_ticket
* @param url 用于签名的 url ,注意必须动态获取,不能 hardcode
*
* @returns
*/
var sign = function (jsapi_ticket, url) {
  var ret = {
    jsapi_ticket: jsapi_ticket,
    noncestr: createNonceStr(),
    timestamp: createTimestamp(),
    url: url
  };

  var string = raw(ret);
      jsSHA = require('jssha');
      shaObj = new jsSHA(string, 'TEXT');
  ret.signature = shaObj.getHash('SHA-1', 'HEX');
  console.log(ret)

  return ret;
};

module.exports = sign;

六.写个接口给前台调用

router.post('/check', function (req, res) {
    let url = decodeURIComponent(req.body.url)
    console.log('url',url)
    res.send(sign(global.jsapiTicket, url))
})

七.invalid signature

        基本上报错都是报的这个,看了很久的社区,总结了一下,可以从以下几个方面入手排查:

1.先保证签名算法正确,校验工具https://mp.weixin.qq.com/debug/cgi-bin/sandbox?t=jsapisign

2.在签名正确的前提下,大概率就是url出问题了。注意以下几个点:传给后台的是否是encodeURIComponent(window.location.href.split('#')[0]);后台是否进行decode解码;配置的安全接口域名是否和页面url一致;url一定要动态获取,每次url变化的时候需要重新进行校验。

  • 24
    点赞
  • 26
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值