如何同时使用express.json与express.raw?表单与Stripe Webhook兼容问题
解决方案
问题的核心在于:Stripe Webhook 的签名验证依赖于请求的原始字节内容,而 express.json() 中间件会将 JSON 请求体解析为 JavaScript 对象,破坏了原始数据的完整性。反之,全局使用 express.raw() 会导致其他需要 JSON 解析的路由无法正常工作。
正确的做法是只为 Stripe Webhook 路由单独应用原始数据中间件,其他路由保持使用 express.json() 处理 JSON 数据。
1. 修改 index.js 配置
移除全局的 express.raw() 中间件,仅将其绑定到 /webhooks 路由:
app.use(express.json()); // 为普通 JSON 请求保留此中间件 app.use(express.static("public")); app.use(express.urlencoded({ extended: true })); app.use(cors()); // 仅对 Webhook 路由应用原始数据中间件 app.post("/webhooks", express.raw({ type: "application/json" }), postStripeWebhook);
2. 修正 Webhook 处理函数
此时 req.body 是 Stripe 发送的原始 Buffer 数据,直接传入 constructEvent 即可,无需额外序列化:
export const postStripeWebhook = async (req: ExtendedRequest, res: Response) => { let data; let eventType; let event; const webhookSecret = "web hook secret provided by stripe"; if (webhookSecret) { const signature = req.headers["stripe-signature"]; try { // 直接使用原始 Buffer 验证签名 event = stripe.webhooks.constructEvent(req.body, signature, webhookSecret); } catch (err) { console.log(`⚠️ Webhook signature verification failed.`); return res.sendStatus(400); } data = event.data; eventType = event.type; } else { // 无签名时,手动解析原始 Buffer 为 JSON const parsedBody = JSON.parse(req.body.toString()); data = parsedBody.data; eventType = parsedBody.type; } let subscription; switch (eventType) { // 处理各类 Webhook 事件 } res.sendStatus(200); };
为什么这样能解决问题?
- 普通 JSON 路由(如登录表单)依然通过
express.json()正常解析请求体。 - Webhook 路由通过
express.raw()获取原始字节数据,完全匹配 Stripe 生成签名时使用的内容,确保验证通过。
内容的提问来源于stack exchange,提问作者Pawan
相关产品推荐
相关产品推荐

