Firebase触发式Cloud Function无法获取用户UID的问题求解
问题分析与解决方案
报错原因
Firestore 的 context.auth 仅在用户通过带身份验证的客户端 SDK 写入数据时才会携带用户信息。你的 subscriptions 文档是通过后端 Admin SDK 创建的,这种服务端写入场景下,触发器的 context.auth 为 undefined,因此读取 context.auth.uid 会抛出类型错误。
解决步骤
1. 在创建订阅文档时存储用户 ID
修改后端 POST 接口,确保写入 subscriptions 文档时,同时存储用户的 UID。需要确保支付系统回传的 decodedJson 中包含用户 ID(前端发起支付请求时,需将当前用户 UID 传递给支付系统,由支付系统带回)。
修改后的后端代码:
app.post("/subscription", (req, res) => { const {data, signature} = req.body; const decodedJson = JSON.parse(Buffer.from(data, "base64")); // 从支付回传数据中提取用户ID(字段名需和支付系统约定) const subscriberId = decodedJson.subscriberId; return admin .firestore() .collection("subscriptions") .doc(decodedJson.order_id) .set({ subscriptionDate: admin.firestore.FieldValue.serverTimestamp(), subscriberId: subscriberId, // 新增存储用户ID data: data, // 存储支付回传的原始数据,供触发器使用 signature: signature // 存储签名,供触发器使用 }) .then(() => { return res.status(200).send("Subscription created"); }) .catch((error) => { throw new Error(error); }); });
2. 修改触发器从文档中获取用户 ID
触发器不再依赖 context.auth.uid,改为从新增的订阅文档快照中读取预存的 subscriberId,同时补充缺失的参数来源并完善批量操作逻辑。
修改后的触发器代码:
exports.checkPaymentStatus = functions.firestore .document("subscriptions/{subscriptionId}") .onCreate(async (snap, context) => { const subscriptionData = snap.data(); // 从文档中获取所需参数 const dataParam = subscriptionData.data; const signature = subscriptionData.signature; const subscriberId = subscriptionData.subscriberId; try { const response = await axios.post("https://paymentsystem.com/api/1/get-status", { data: dataParam, signature: signature, }); if (response.data.status === "success") { const batch = admin.firestore().batch(); // 标记订阅支付成功(可选) batch.update(snap.ref, { paymentStatus: "success" }); // 更新用户的Pro状态 batch.update(admin.firestore().collection("users").doc(subscriberId), { isPro: true, subscribedDate: admin.firestore.FieldValue.serverTimestamp(), }); // 提交批量更新操作 await batch.commit(); } else { // 标记支付失败状态(可选) await snap.ref.update({ paymentStatus: "failed" }); } } catch (error) { console.error("Error occurred:", error); // 标记错误状态(可选) await snap.ref.update({ paymentStatus: "error", errorMessage: error.message }); } });
额外注意事项
- 需和支付系统约定回传数据格式,确保包含用户 UID 字段。
- 使用
async/await替代嵌套then/catch,提升代码可读性和可维护性。 - 批量操作必须调用
batch.commit()才能生效,原代码遗漏了此步骤。 - 新增的
paymentStatus字段可用于后续排查支付状态问题。
内容的提问来源于stack exchange,提问作者Amor Soma
相关产品推荐
相关产品推荐

