React-Native集成Stripe时Firebase云函数报400错误如何修复?
React-Native 集成 Firebase Cloud Functions + Stripe 400错误排查方案
你的报错是云函数类型不匹配、参数写法错误、请求逻辑错误叠加导致的,按以下方向逐一排查修正即可:
- 云函数类型和调用方式完全不匹配:你定义云函数用的是
onCall(Firebase专属可调用函数),但前端用fetch发普通HTTP POST请求,onCall类型函数要求请求带固定格式的鉴权头、结构化请求体,普通fetch请求不符合协议要求,会直接触发Request is missing body/Invalid request的400错误。 - Stripe SDK参数写法错误:调用
stripe.paymentIntents.create时多余套了一层data字段,Stripe Node SDK要求直接传入配置对象,外层包data会导致参数无法被正确识别。 onCall函数返回逻辑错误:onCall函数的第二个参数是上下文对象,不是HTTP响应对象,不需要也不能用response.json()返回结果,直接return目标对象即可。- 前端请求逻辑错误:一是请求路径和云函数导出名不匹配,你导出的函数名是
payWithStripe,前端请求的路径是/create-payment-intent,路径根本对应不上;二是POST请求没有传body字段,就算是普通HTTP接口也会触发缺请求体报错。
修正代码(二选一即可,新手推荐选onRequest方案,逻辑更直观)
方案1:使用onRequest类型云函数(适配普通fetch调用)
云函数index.js代码
// 提前初始化Stripe,替换为你自己的Stripe服务端秘钥 const stripe = require('stripe')('你的Stripe服务端秘钥'); // 导出名称和前端请求路径保持一致 exports.createPaymentIntent = functions.https.onRequest(async (req, res) => { // 配置跨域,否则React-Native端请求会被拦截 res.set('Access-Control-Allow-Origin', '*'); res.set('Access-Control-Allow-Headers', 'Content-Type'); // 处理预检请求 if (req.method === 'OPTIONS') { res.status(204).send(''); return; } try { const paymentIntent = await stripe.paymentIntents.create({ amount: 100, // Stripe金额按最小货币单位计算,100对应1美元 currency: "usd", payment_method_types: ["card"] }); res.json({ clientSecret: paymentIntent.client_secret, }) } catch (e) { console.log(e.message); res.status(400).json({ error: e.message }); } })
对应前端请求代码
const fetchPaymentIntentClientSecret = async () => { const response = await fetch(`${FUNCTION_URL}/createPaymentIntent`, { method: "POST", headers: { "Content-Type": "application/json", }, // POST请求即使不传参数也要传空body,避免触发缺body报错 body: JSON.stringify({}) }); if (!response.ok) { const errRes = await response.json(); return { clientSecret: null, error: errRes.error }; } const { clientSecret, error } = await response.json(); return { clientSecret, error }; }
方案2:使用onCall可调用函数(需要搭配Firebase SDK调用)
云函数index.js代码
const stripe = require('stripe')('你的Stripe服务端秘钥'); exports.payWithStripe = functions.https.onCall(async (data, context) => { try { const paymentIntent = await stripe.paymentIntents.create({ amount: 100, currency: "usd", payment_method_types: ["card"] }); // onCall函数直接return结果即可,不需要操作响应对象 return { clientSecret: paymentIntent.client_secret, } } catch (e) { console.log(e.message); // onCall错误需要按官方指定格式抛出 throw new functions.https.HttpsError('internal', e.message); } })
对应前端请求代码
import { getFunctions, httpsCallable } from "firebase/functions"; const functions = getFunctions(); const payWithStripeRequest = httpsCallable(functions, 'payWithStripe'); const fetchPaymentIntentClientSecret = async () => { try { const res = await payWithStripeRequest(); return { clientSecret: res.data.clientSecret, error: null }; } catch (e) { return { clientSecret: null, error: e.message }; } }
额外排查项
- 确认
FUNCTION_URL配置正确:本地调试要填对模拟器对应的端口,线上部署要填Firebase分配的云函数域名,不要漏写项目路径前缀。 - 确认云函数环境配置的Stripe秘钥是服务端秘钥(以sk_开头),不要误填客户端公钥(以pk_开头)。
- 云函数部署完成后等待1-2分钟再发起请求,刚部署完成的函数冷启动阶段可能偶发请求异常。
内容的提问来源于stack exchange,提问作者Scorch
相关产品推荐
相关产品推荐

