本文分二个部分,第一个部分先介绍微信开发中,access_token和jsapi_ticket是最关键的凭证。
相信许多开发者习惯自己实现这些凭证的获取和管理,扫码需要,然后自动 login 需要。 但在UniCloud环境下,我更推荐的一种方式是使用 uni-open-bridge-common 模块来实现相关的功能。 它提供了更加统一和可靠的解决方案。本文详细介绍这两种凭证的管理方式及最佳实践。
微信凭证介绍
access_token
access_token是调用微信接口的全局唯一凭证,由appid和secret获取,有效期通常为7200秒(2小时)。它用于调用各种微信API,如获取用户信息、发送模板消息等。
关于微信的access_token,有几个重要特性需要理解:
access_token的全局唯一性
-
全局唯一性:对于同一个微信应用(同一个AppID),access_token是全局唯一的
-
互相覆盖问题:当有人获取了新的access_token,之前的token会立即失效
-
这在微信官方文档中明确说明:"重复获取将导致上次获取的access_token失效"
-
所以如果多个系统都使用相同的AppID各自获取token,会导致相互间的token失效
-
-
实际影响:
-
系统A获取token → 可以正常使用
-
系统B也获取token → 系统A的token立即失效
-
系统A使用失效token调用接口 → 报错"invalid credential"
-
jsapi_ticket
jsapi_ticket是用于微信JS-SDK的临时票据,通过access_token获取,同样有效期为7200秒。它用于生成JS-SDK权限验证的签名,用于网页中调用微信JS-SDK的各种功能。
传统实现方式及问题
传统实现示例
// 获取access_token
async function getAccessToken() {
const url = `https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=${appid}&secret=${secret}`;
const res = await fetch(url);
const data = await res.json();
// 存储到缓存
await redis.set('wx_access_token', data.access_token, 'EX', 7000);
return data.access_token;
}
// 获取jsapi_ticket
async function getJsapiTicket() {
const token = await getAccessToken();
const url = `https://api.weixin.qq.com/cgi-bin/ticket/getticket?access_token=${token}&type=jsapi`;
const res = await fetch(url);
const data = await res.json();
// 存储到缓存
await redis.set('wx_jsapi_ticket', data.ticket, 'EX', 7000);
return data.ticket;
}
存在的问题
- 各应用独立实现:不同云函数可能各自实现获取凭证的逻辑
- 凭证冲突:相同appid的凭证被多个系统独立获取,导致之前获取的失效
- 请求频率限制:微信对获取凭证有频率限制,容易触发限制
- 存储不统一:缓存键命名不一致,难以管理
- 缺乏更新机制:没有考虑凭证提前失效的情况
uni-open-bridge-common解决方案
模块优势
- 统一管理:集中管理所有微信凭证
- 分类存储:根据不同平台(小程序、公众号等)和appid分别存储
- 多层缓存:同时使用数据库和Redis缓存,保证可靠性
- 自动刷新:内置更新机制,处理凭证失效
- 跨云函数共享:所有云函数可共享同一套凭证
使用的URL
-
access_token获取URL:
- 稳定版接口:
https://api.weixin.qq.com/cgi-bin/stable_token(POST请求) - 传统接口:
https://api.weixin.qq.com/cgi-bin/token(GET请求,已不推荐)
- 稳定版接口:
-
jsapi_ticket获取URL:
https://api.weixin.qq.com/cgi-bin/ticket/getticket?type=jsapi(POST请求)
1. 获取access_token
const { getAccessToken } = require("uni-open-bridge-common");
async function getWXAccessToken() {
try {
const result = await getAccessToken({
dcloudAppid: "__UNI__77XXXX", // 应用的DCloud AppID
provider: "weixin-h5", // 平台类型:weixin-mp(小程序)、weixin-h5(公众号)等
appid: "wx1234567890", // 微信AppID
secret: "abcdefg1234567890" // 微信AppSecret
});
return result.access_token;
} catch (error) {
console.error("获取access_token失败:", error);
throw error;
}
}
2. 获取jsapi_ticket
const { getTicket } = require("uni-open-bridge-common");
async function getWXTicket() {
try {
const result = await getTicket({
dcloudAppid: "__UNI__77XXXX", // 应用的DCloud AppID
provider: "weixin-h5", // 平台类型:weixin-mp(小程序)、weixin-h5(公众号)等
});
return result.ticket;
} catch (error) {
console.error("获取jsapi_ticket失败:", error);
throw error;
}
}
大家有没有注意到,上面其实不用先取 access_token, 理论上自己实现(见上文),是需要传 AccessToken 才可以取得到 获取jsapi_ticket. 这说一下 uni-open-bridge-common 是通过什么机制获取这些信息的:
- 配置中心读取:模块会从uni-config-center的uni-id配置中读取凭证信息
// uni-open-bridge-common内部的AppConfig类
getAppConfig(appid) {
// 从uni-id配置中读取
const uniIdConfig = configCenter({ pluginId: 'uni-id' }).config()
// ...
}
- 需要正确配置:您必须确保在commone/uni-config-center/uni-id/config.json中已配置了微信应用信息:
{
"web": {
"oauth": {
"weixin-h5": {
"appid": "wx123456789",
"appsecret": "abcdef123456789"
}
}
}
}
- 查找逻辑:当您传入dcloudAppid和provider时,系统会:
- 根据dcloudAppid找到对应的uni-id配置
- 根据provider找到相应的微信应用配置
- 从配置中获取appid和secret
3. 强制刷新token
const { updateAccessToken } = require("uni-open-bridge-common");
async function refreshToken() {
try {
await updateAccessToken({
dcloudAppid: "__UNI__7741880",
provider: "weixin-h5"
});
console.log("access_token已强制刷新");
} catch (error) {
console.error("刷新access_token失败:", error);
throw error;
}
}
验证存储是否成功
在Redis中查询
Redis存储格式
-
连接到UniCloud 后台 Redis(通过控制台或Redis客户端)
-
查询access_token:
键名:uni-id:<provider>:<appid>:access-token
KEYS uni-id:weixin-h5:*:access-token后台可以直接输入 :access-token。全局只有一条。根据 provider 和 appid 来确认全局。
-
查询ticket:
键名:uni-id:<provider>:<appid>:ticket
KEYS uni-id:weixin-h5:*:ticket后台可以直接输入:ticket查看,会有很多。每个用户一条。
-
获取具体值:
GET uni-id:weixin-h5:wxaefc501c799f7d92:access-token
在数据库中查询
- 打开
opendb-open-data集合 - 查询条件:
_id包含access-token或ticket - 值应该包含有效的JSON数据,包括过期时间
多应用场景下的最佳实践
情况1:相同云空间不同应用使用不同AppID
这是理想情况,每个应用使用独立的微信凭证。uni-open-bridge-common通过dcloudAppid和provider区分,不会产生冲突。
情况2:相同云空间不同应用使用相同AppID
此情况下会共享凭证,需要确保:
- 所有应用使用
uni-open-bridge-common获取凭证 - 不要在不同应用中使用自定义实现获取凭证
- 如有特殊需求,可考虑不同应用使用不同的provider类型
情况3:支付场景
支付相关功能也需要access_token,建议:
- 修改支付模块使用
uni-open-bridge-common获取凭证 - 确保支付用的provider(如weixin-mp)与公众号(weixin-h5)不同
- 如果必须使用相同provider,则确保所有云函数都使用统一的获取方式
注意事项和常见问题
-
凭证失效问题:如遇到"invalid credential"错误,可以尝试:
- 使用
updateAccessToken强制刷新 - 确认appid和secret配置正确
- 检查微信公众平台IP白名单配置
- 使用
-
多环境部署:dev/test/prod环境应使用不同的appid,避免相互影响
-
不建议混用:不要在同一应用中混用
uni-open-bridge-common和自定义实现 -
注意平台类型:
weixin-mp(小程序)、weixin-h5(公众号)、weixin-web(H5应用)在内部处理上有差异
总结
uni-open-bridge-common模块为UniCloud环境下的微信凭证管理提供了统一、可靠的解决方案。通过标准化的键名格式、多层缓存策略和自动刷新机制,大大简化了开发者的工作,提高了微信凭证管理的效率和可靠性。
在新项目中,强烈建议使用uni-open-bridge-common替代自定义实现;在现有项目中,建议逐步迁移到该模块,确保凭证管理的稳定性和一致性。