Firebase集成Express时,Stripe Webhook使用express.raw失效问题
问题背景
在Firebase云函数中用Express配置Stripe Webhook时,始终触发签名验证错误:
"Webhook Error: No signatures found matching the expected signature for payload. Are you passing the raw request body you received from Stripe?"
尝试了Express官方推荐的express.raw({type: 'application/json'})、条件跳过JSON解析等多种方案均无效,但改用Firebase原生onRequest方法直接读取req.rawBody后,验证立刻通过。核心疑问是Express方案失效的原因,以及如何让Express方案正常工作。
核心原因
Firebase云函数的HTTP触发器默认会提前自动解析请求体,导致Express中间件拿到的不是Stripe需要的原始请求字节数据。
Stripe的签名验证要求完全匹配请求的原始字节内容,但Firebase在把请求转发给Express应用之前,已经对请求体做了解析、编码转换等处理,Express拿到的req.body是经过Firebase处理后的版本,和Stripe发送的原始数据存在差异,因此无法通过签名验证。
而原生onRequest方法中,req.rawBody直接保留了Firebase接收到的原始请求字节,没有经过任何解析修改,所以能通过Stripe的签名校验。
解决Express方案的方法
要在Firebase上用Express正常处理Stripe Webhook,核心是绕过Firebase的自动解析,确保拿到原始请求体。
方法1:禁用云函数的自动请求体解析
导出云函数时配置rawBody: true,让Express直接处理原始请求:
const express = require('express'); const app = express(); const stripe = require('stripe')(functions.config().stripe.secret_key); // Webhook路由直接使用raw中间件处理原始请求 app.post('/webhook', express.raw({ type: 'application/json' }), (req, res) => { const webhookSecret = functions.config().stripe.webhook_secret_key; let event; try { event = stripe.webhooks.constructEvent( req.body, req.headers['stripe-signature'], webhookSecret ); } catch (err) { return res.status(400).send(`Webhook Error: ${err.message}`); } // 编写你的Webhook事件处理逻辑 // ... res.json({ received: true }); }); // 导出云函数时禁用自动解析,保留原始请求体 exports.stripeApi = functions.https.onRequest({ rawBody: true }, app);
方法2:直接从Firebase请求对象获取原始体
如果无法全局禁用自动解析,可在Express中间件里直接读取Firebase附加的rawBody字段:
const express = require('express'); const app = express(); const stripe = require('stripe')(functions.config().stripe.secret_key); // 不需要额外的raw中间件,直接用Firebase提供的rawBody app.post('/webhook', (req, res) => { const webhookSecret = functions.config().stripe.webhook_secret_key; let event; try { event = stripe.webhooks.constructEvent( req.rawBody.toString(), req.headers['stripe-signature'], webhookSecret ); } catch (err) { return res.status(400).send(`Webhook Error: ${err.message}`); } // 编写你的Webhook事件处理逻辑 // ... res.json({ received: true }); }); exports.stripeApi = functions.https.onRequest(app);
总结
Firebase云函数默认的请求体解析行为是Express方案失效的关键,它破坏了Stripe签名验证所需的原始请求数据一致性。通过禁用自动解析或直接读取req.rawBody,就能在Express中正常处理Stripe Webhook,实现代码统一管理。
内容的提问来源于stack exchange,提问作者seth8656

