如何在Cloud Function中正确查询Firebase实时数据库获取定价数据?
问题描述
我尝试根据存储定价数据所属的用户进行查询,将结果返回到Stripe结账的Cloud Function中,但一直收到变量未赋值的错误。查了相关文档后还是困惑,参考了一些类似实现的资源反而把代码搞乱了。请问如何正确从数据库获取定价信息并填入Stripe的结账参数里?
实时数据库数据结构
studiopick studio users Gcsh31DCGAS2u2XXLuh8AbwBeap1 email : "Test@gmail.com" firstName : "Test" lastName : "one" phoneNumber : "2223334567" prices | roomA | serviceOne | numberInput : "300" | serviceType : "mix n master" studioName : "Studio One" uid : "Gcsh31DCGAS2u2XXLuh8AbwBeap1"
现有Cloud Function代码
const functions = require("firebase-functions"); const admin = require("firebase-admin"); let price; let info; admin.initializeApp(functions.config().firebase); exports.createStripeCheckout = functions.https.onCall(async (data, context) => { const querySnapshot = await ref .orderByChild("numberInput, serviceInput") .equalTo(price, info) .once("value"); // Stripe init const stripe = require("stripe")(functions.config().stripe.secret_key); const session = await stripe.checkout.sessions.create({ payment_method_types: ["card"], mode: "payment", success_url: "http://localhost:5500/success", cancel_url: "http://localhost:5500/cancel", shipping_address_collection: { allowed_countries: ["US"], }, line_items: [ { quantity: 1, price_data: { currency: "usd", unit_amount: price * 100, // 10000 = 100 USD product_data: { name: info, }, }, }, ], }); return { id: session.id, }; }); exports.stripeWebhook = functions.https.onRequest(async (req, res) => { const stripe = require("stripe")(functions.config().stripe.token); let event; try { const whSec = functions.config().stripe.payments_webhook_secret; event = stripe.webhooks.constructEvent( req.rawBody, req.headers["stripe-signature"], whSec ); } catch (err) { console.error("⚠️ Webhook signature verification failed."); return res.sendStatus(400); } const dataObject = event.data.object; await admin.firestore().collection("orders").doc().set({ checkoutSessionId: dataObject.id, paymentStatus: dataObject.payment_status, shippingInfo: dataObject.shipping, amountTotal: dataObject.amount_total, }); return res.sendStatus(200); });
解决方案
原代码核心问题
- 全局变量
price、info未初始化,也没有从数据库赋值的逻辑 - 数据库查询的
ref未定义,且orderByChild/equalTo用法错误(Firebase实时数据库不支持同时按多个字段排序/匹配) - 未利用Callable Function的
context.auth.uid获取当前用户ID,无法定位到对应用户的定价数据
修复后的完整代码
const functions = require("firebase-functions"); const admin = require("firebase-admin"); // 提前引入Stripe,避免重复require const stripe = require("stripe")(functions.config().stripe.secret_key); admin.initializeApp(functions.config().firebase); exports.createStripeCheckout = functions.https.onCall(async (data, context) => { // 验证用户是否已登录 if (!context.auth) { throw new functions.https.HttpsError( "unauthenticated", "用户未登录,无法创建结账会话" ); } const userId = context.auth.uid; // 构建数据库引用,定位到当前用户的serviceOne定价节点 const priceRef = admin.database().ref(`studiopick/studio/users/${userId}/prices/roomA/serviceOne`); try { // 读取定价数据 const snapshot = await priceRef.once("value"); const priceData = snapshot.val(); if (!priceData) { throw new functions.https.HttpsError( "not-found", "未找到该用户的定价信息" ); } // 转换价格为数字(数据库中是字符串) const unitAmount = parseInt(priceData.numberInput) * 100; const serviceName = priceData.serviceType; // 创建Stripe结账会话 const session = await stripe.checkout.sessions.create({ payment_method_types: ["card"], mode: "payment", success_url: "http://localhost:5500/success", cancel_url: "http://localhost:5500/cancel", shipping_address_collection: { allowed_countries: ["US"], }, line_items: [ { quantity: 1, price_data: { currency: "usd", unit_amount: unitAmount, product_data: { name: serviceName, }, }, }, ], }); return { id: session.id }; } catch (error) { console.error("创建结账会话失败:", error); throw new functions.https.HttpsError( "internal", "创建结账会话时发生错误", error.message ); } }); exports.stripeWebhook = functions.https.onRequest(async (req, res) => { const stripeWebhook = require("stripe")(functions.config().stripe.token); let event; try { const whSec = functions.config().stripe.payments_webhook_secret; event = stripeWebhook.webhooks.constructEvent( req.rawBody, req.headers["stripe-signature"], whSec ); } catch (err) { console.error("⚠️ Webhook签名验证失败:", err); return res.sendStatus(400); } const dataObject = event.data.object; await admin.firestore().collection("orders").doc().set({ checkoutSessionId: dataObject.id, paymentStatus: dataObject.payment_status, shippingInfo: dataObject.shipping, amountTotal: dataObject.amount_total, }); return res.sendStatus(200); });
关键修复点说明
- 用户身份验证:通过
context.auth.uid获取当前登录用户ID,确保只查询该用户的定价数据 - 正确的数据库引用:直接定位到用户的
serviceOne定价节点,无需复杂查询(因为数据结构是按用户UID组织的) - 数据类型转换:将数据库中存储的字符串价格转换为整数,再乘以100适配Stripe的分单位
- 错误处理:添加了用户未登录、定价数据不存在的错误捕获,返回标准化的HttpsError
- 代码优化:提前引入Stripe,避免在函数内部重复require
内容的提问来源于stack exchange,提问作者Grmln
相关产品推荐
相关产品推荐

