Stripe Webhook签名验证失败问题求助
解决Stripe Webhook签名验证错误:No signatures found matching the expected signature for payload
核心问题分析
你的代码存在关键错误:路由已经通过express.raw({ type: "application/json" })保留了Stripe发送的原始请求体(格式为Buffer),但后续又执行了JSON.stringify(req.body),这会把原始Buffer转换成完全不符合预期的字符串(例如{"type":"Buffer","data":[...]}),导致Stripe无法匹配签名。
Stripe的签名是基于它发送的原始HTTP请求体生成的,任何对请求体的修改(包括重新序列化、转义字符变化)都会直接导致签名验证失败。
修正方案
直接使用express.raw解析后的原始请求体,无需额外序列化操作:
修正后的Webhook处理函数
export const sessionUpdate = async (req, res) => { const sig = req.headers['stripe-signature']; const stripeInstance = Stripe(process.env.STRIPE_SECRET_KEY); let event; // 直接使用express.raw返回的原始请求体(constructEvent支持Buffer或字符串格式) const rawBody = req.body; try { event = stripeInstance.webhooks.constructEvent(rawBody, sig, process.env.ENDPOINT_SECRET); } catch (err) { console.error('Webhook Error:', err.message); return res.status(400).send(`Webhook Error: ${err.message}`); } if (!event || !event.type) { console.error('Invalid event data:', event); return res.status(400).json({ error: 'Invalid event data' }); } console.log('Received event:', event.type); switch (event.type) { case 'checkout.session.completed': try { const completedEvent = event.data.object; const { metadata } = completedEvent; const { post_id } = metadata; const updatedPost = await Post.findByIdAndUpdate( post_id, { paymentStatus: true }, { new: true } ); if (!updatedPost) { return res.status(404).json({ error: 'Post not found' }); } return res.json({ message: 'Post status updated successfully', updatedPost }); } catch (error) { console.error('Error updating post status:', error); return res.status(500).json({ error: 'Internal server error' }); } default: console.log(`Unhandled event type ${event.type}`); return res.status(200).end(); } };
补充验证点
- 确认
process.env.ENDPOINT_SECRET是Stripe Dashboard中Webhook端点的签名密钥(以whsec_开头),而非普通API密钥。 - 检查是否有其他中间件(如body-parser的其他实例)在
express.raw之前修改了请求体,确保express.raw是该路由的第一个处理中间件。 - 使用Stripe CLI测试时,确认转发的本地地址与代码路由完全匹配,且没有额外代理层修改请求体。
内容的提问来源于stack exchange,提问作者Youssef KH
相关产品推荐
相关产品推荐

