1.问题背景
使用腾讯云模板的微信支付模板处理支付,在回调函数中发送订阅消息会出现errCode: -501007 | errMsg: subscribeMessage.send:fail missing wxCloudApiToken的错误,但是手动触发订阅函数却可以发送消息。
2.问题分析
根本原因
微信支付/退款回调是系统触发,不是用户通过小程序调用:
用户操作 → 小程序 → 云函数 → cloud.openapi.* 有用户上下文
微信系统 → 直接回调云函数 → cloud.openapi.* 无用户上下文
查看 cloud.getWXContext() 返回值:
// 手动调用(成功)
{
OPENID: "12345...",
APPID: "wx1234...",
ENV: "cloudbase-...",
SOURCE: "wx_client"
}
// 支付回调(失败)
{
APPID: "wx1234...",
ENV: "cloudbase-...",
SOURCE: ",scf" // ← 注意这里
// 缺少 OPENID!
}
结论:cloud.openapi.* 需要 wxCloudApiToken,Token 来自用户会话上下文
回调场景缺少用户会话 → 无法获取 Token
3.解决办法
使用微信服务端 HTTP API 替代 cloud.openapi.*
1. 创建 access_token 管理工具
// utils/accessToken.js
const { cloud, db } = require("./database");
async function getAccessToken() {
// 1. 检查缓存
const cached = await getCachedAccessToken();
if (cached) return cached;
// 2. 从微信服务器获取
//const url = `https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=${appid}&secret=${secret}`;
//使用以上网址获取access_token,appid为微信小程序ID,secret为小程序密钥
const { access_token } = await fetchAccessToken();
// 3. 缓存7200秒
await saveAccessToken(access_token);
return access_token;
}
2. 修改订阅消息发送方法
// utils/subscribeMessage.js
async function sendSubscribeMessageViaHTTP(params) {
const accessToken = await getAccessToken();
const url = `https://api.weixin.qq.com/cgi-bin/message/subscribe/send?access_token=${accessToken}`;
const axios = require("axios");
//参数与subscribeMessage.send一致
const response = await axios.post(url, params);
return response.data;
}
3. 获取用户 openid
方法一:从回调参数中获取(支付回调)
// 支付回调数据
resource: {
payer: { openid: '1234......' }
}
const payerOpenid = event.resource?.payer?.openid;
方法二:从数据库查询(退款回调)
// 订单 → userId → openid
const userResult = await db.collection("users")
.doc(order.userId)
.get();
const openid = userResult.data.openid;
这样就可以实现回调函数中发送订阅消息,希望能帮到大家
