近期在写一个微信公众号网站,需要用到微信扫一扫功能。去微信开发文档发现JS-SDK可以实现这个功能,调用接口需要先获取 access_tokenjsapi_ticket,但是微信对这两个接口每天的调用次数都有限制。考虑到 access_tokenjsapi_ticket都会在生成后的7200秒内有效,可以将 jsapi_ticket存在数据库中,然后每小时刷新一次数据,这样可以减少接口的调用次数,在此记录一下实现的过程。

获取access_token

官方文档:https://developers.weixin.qq.com/doc/offiaccount/Basic_Information/Get_access_token.html

通过接口https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=APPID&secret=APPSECRET获取 access_token值,APPID和APPSECRET可以在公众号开发信息中找到。

这里使用的是 request-promise模块:

const request = require("request-promise");
const wxConfig = {
    AppID: 'xxx',
    AppSecret: 'xxx'
}
let url = `https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=${wxConfig.AppID}&secret=${wxConfig.AppSecret}`;
request(url).then(res => {
    console.log(JSON.parse(res).access_token);    
})

获取jsapi_ticket

通过接口https://api.weixin.qq.com/cgi-bin/ticket/getticket?access_token=ACCESS_TOKEN&type=jsapi获取 jsapi_ticket的值:

let url = `https://api.weixin.qq.com/cgi-bin/ticket/getticket?access_token=${JSON.parse(res).access_token}&type=jsapi`
request(url).then(res => {
    resolve(JSON.parse(res).ticket)
})

到这里可以将上面两步封装成一个函数:

function getTicket(wxConfig) {
    return new Promise((resolve, reject) => {
        let url = `https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=${wxConfig.AppID}&secret=${wxConfig.AppSecret}`;
        request(url).then(res => {
            url = `https://api.weixin.qq.com/cgi-bin/ticket/getticket?access_token=${JSON.parse(res).access_token}&type=jsapi`
            request(url).then(res => {
                resolve(JSON.parse(res).ticket)
            })
        })
    })
}

将jsapi_ticket存储在MongoDB中

创建数据模型:

const mongoose = require("mongoose");
const Schema = mongoose.Schema;

const WxTokenSchema = new Schema({
    jsapi_ticket: {
        required: true,
        type: String
    },
});
module.exports = Wxtoken = mongoose.model("wxToken", WxTokenSchema);

插入或更新数据:

const WxToken = require("../../models/WxToken");

function resetTicket() {
    WxToken.find().then(data => {
        if (data.length) {
            getTicket(wxConfig).then(ticket => {
                data[0].jsapi_ticket = ticket
                data[0].save()
            })
        } else {
            getTicket(wxConfig).then(ticket => {
                WxToken.create({
                    'jsapi_ticket': ticket
                })
            })
        }
    })
}

每个一小时刷新数据:

setInterval(() => {
    resetTicket()
}, 1000 * 60 * 60)

生成签名和返回路由数据

签名算法官方文档:https://developers.weixin.qq.com/doc/offiaccount/OA_Web_Apps/JS-SDK.html#62
const crypto = require('crypto');

router.get('/', function (req, res) {
    WxToken.findOne().then(data => {
        let noncestr = Math.random() * 10000000
        let jsapi_ticket = data.jsapi_ticket
        let timestamp = new Date().getTime()
        let url = 'http://test.no0a.cn/'
        let string = `jsapi_ticket=${jsapi_ticket}&noncestr=${noncestr}&timestamp=${timestamp}&url=${url}`
        let signature = crypto.createHash('sha1').update(string).digest('hex')

        res.json({
            status: 200,
            data: {
                appId: wxConfig.AppID,
                timestamp,
                noncestr,
                signature
            }
        })
    })
})

前端获取数据并调用微信扫一扫接口

wx.config({
    debug: true, // 开启调试模式,调用的所有api的返回值会在客户端alert出来,若要查看传入的参数,可以在pc端打开,参数信息会通过log打出,仅在pc端时才会打印。
    appId: '', // 必填,公众号的唯一标识
    timestamp: '', // 必填,生成签名的时间戳
    nonceStr: '', // 必填,生成签名的随机串
    signature: '', // 必填,签名
    jsApiList: ['scanQRCode'] // 必填,需要使用的JS接口列表
});

wx.scanQRCode({
    needResult: 1, // 默认为0,扫描结果由微信处理,1则直接返回扫描结果,
    scanType: ["qrCode", "barCode"], // 可以指定扫二维码还是一维码,默认二者都有
    success(res) {
        console.log(res.resultStr)
    }
})

到这里就可以调用微信扫一扫功能了。

最后修改:2020 年 08 月 04 日 04 : 49 PM
如果觉得我的文章对你有用,请随意赞赏