Stripe Webhook签名验证失败:未提供负载,如何解决?
问题
我正尝试在应用中集成Stripe API,但接收Webhook数据时遇到错误。完成成功收费后,代码返回如下错误提示:
router.post('/webhook', async (req, res) => { console.log("Received request"); let data; let eventType; // Check if webhook signing is configured. const webhookSecret = stripeWebhookSigningKey; if (webhookSecret) { // Retrieve the event by verifying the signature using the raw body and secret. let event; let signature = req.headers['stripe-signature']; try { event = stripe.webhooks.constructEvent( req['rawBody'], signature, webhookSecret ); } catch (err) { console.log(`⚠️ Webhook signature verification failed: ` + err); return res.sendStatus(400); } // Extract the object from the event. data = event.data; eventType = event.type; } else { // Webhook signing is recommended, but if the secret is not configured in `config.js`, // retrieve the event data directly from the request body. data = req.body.data; eventType = req.body.type; } switch (eventType) { case 'checkout.session.completed': console.log(data); break; case 'invoice.paid': console.log(data); break; case 'invoice.payment_failed': console.log(data); break; default: // Unhandled event type console.log(data); break; } res.sendStatus(200); });
⚠️ Webhook signature verification failed: Error: No webhook payload was provided.
有用户反馈该问题源于响应JSON格式错误,我已在脚本顶部添加如下代码修复,但仍无效果:
router.use( express.json({ verify: (req, res, buffer) => (req['rawBody'] = buffer), }) );
Stripe CLI工具明确已发送请求,但日志显示HTTP 400状态。请问问题出在哪里,该如何解决?
可能的原因及解决方法
1. 中间件加载顺序错误
确保配置的express.json()中间件在webhook路由定义之前加载。如果中间件在路由之后执行,req.rawBody不会被提前设置,导致constructEvent无法获取原始请求 payload。
正确顺序示例:
// 先加载带verify的json中间件 router.use( express.json({ verify: (req, res, buffer) => (req['rawBody'] = buffer), }) ); // 再定义webhook路由 router.post('/webhook', async (req, res) => { // 你的路由逻辑 });
2. 其他中间件提前解析了请求体
如果应用中存在其他解析请求体的中间件(比如express.urlencoded()或第三方中间件),它们可能会先于你配置的express.json()处理请求,导致原始buffer丢失。
解决方式:只为webhook路由单独配置带verify的json中间件,避免全局中间件干扰:
// 直接在webhook路由中挂载专属中间件 router.post('/webhook', express.json({ verify: (req, res, buffer) => (req['rawBody'] = buffer), }), async (req, res) => { // 你的路由逻辑 } );
3. 签名密钥配置错误
确认stripeWebhookSigningKey使用的是Stripe Dashboard中对应webhook端点的签名密钥(以whsec_开头),而非普通API密钥。密钥不匹配会直接导致签名验证失败,触发类似报错。
4. Stripe CLI 转发路径不匹配
检查Stripe CLI的转发命令是否指向正确的路由路径。例如你的路由是/webhook,确保CLI命令为:
stripe listen --forward-to localhost:3000/webhook
5. 验证req.rawBody是否正确设置
在constructEvent执行前添加日志,确认req.rawBody和签名头是否存在:
console.log('Raw body exists:', !!req.rawBody); console.log('Stripe signature:', req.headers['stripe-signature']);
如果req.rawBody为undefined,说明中间件的verify函数未正确执行,需要重新排查中间件配置逻辑。
内容的提问来源于stack exchange,提问作者Samuel stankiewicz

