集成微信 JS-SDK - 基于 node 实现
ON THIS PAGE
在微信中打开的 H5 ,可以调用微信提供的原生功能,如拍照 / 自定义分享等。要想调用这些功能,需要先集成微信JS-SDK。
集成微信JS-SDK有两个前置条件:
注册好的微信公众号。不同的公众号类型,获取的权限也不同,具体可以点这里查看
域名已备案
公众号后台配置
设置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}×tamp=${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);
2020-05-31