Stripe Webhook签名验证失败:未找到匹配预期载荷的签名
Stripe Webhook签名验证失败问题排查与解决
我在用Stripe创建结账会话,会话完成时Webhook能触发,但一直收到错误:
"error": "No signatures found matching the expected signature for payload. Are you passing the raw request body you received from Stripe?"已确认Webhook签名密钥正确,试过
express.raw({type: 'application/json'})、bodyParser.raw(),还加了自定义中间件,都没解决问题。
我的当前代码
主路由代码
const stripeRouter = express.Router({ mergeParams: true }); const endPointSecret = 'Webook_Secret' stripeRouter.post('/webhook', express.raw({type: 'application/json'}), async (req: express.Request, res: express.Response) => { const stripe = await getStripe(); await getStripeSecretKey(); const sig = req.headers['stripe-signature']; console.log(`signature: ${sig}`) const payload = req.body; console.log(`payload: ${payload}`) let eventType; let data; if (endPointSecret) { let event; try { event = stripe.webhooks.constructEvent(payload, sig, endPointSecret); console.log(`$$$$$ Webhook Verification Successful`) } catch (err) { console.log(`$$$$$ Webhook signature verification failed`, err.message) res.status(400).json({error: err.message, signature: req.body}); return; } eventType = event.type; data = event.data; console.log(`$$$ EVENT TYPE: ${eventType}`) console.log(`$$$ DATA: ${data}`) } else { data = req.body.data.object; eventType = req.body.type; } })
尝试过的自定义中间件
stripeRouter.use((req: express.Request, res: express.Response, next: express.NextFunction) => { if (req.originalUrl === '/webhook') { next(); } else { express.json()(req, res, next); } })
排查与解决步骤
- 优先排查全局中间件干扰:检查你的Express应用是否在全局级别注册了
express.json()或bodyParser.json(),这类中间件会提前解析请求体,破坏Stripe签名验证依赖的原始请求数据。要确保webhook路由在这些全局中间件之前注册,或者通过配置排除webhook路径。 - 验证签名头完整性:打印
sig值,确认它是完整的Stripe签名格式(类似t=1690000000,v1=abcdef123456,v0=ghijkl789012),如果是undefined或截断状态,检查反向代理(Nginx、Cloudflare等)是否传递了所有Stripe请求头。 - 锁定签名密钥环境:确认
endPointSecret是Stripe Dashboard对应Webhook端点的签名密钥,且区分测试/生产环境,不要和API密钥混淆。 - 强制保留原始请求体:修改
express.raw配置,手动保存原始Buffer到请求对象,避免中间件隐式转换:
之后用express.raw({ type: 'application/json', verify: (req, res, buf) => { (req as any).rawBody = buf; } })req.rawBody作为constructEvent的payload参数。 - 提前初始化Stripe客户端:不要在请求处理函数里异步获取Stripe实例和密钥,建议在应用启动时完成初始化,避免验证时客户端未就绪的问题。
- 用Stripe CLI测试:通过
stripe listen --forward-to localhost:3000/webhook转发测试事件,CLI会自动生成合法签名,快速定位是代码问题还是生产环境网络/代理问题。
内容的提问来源于stack exchange,提问作者JD258
相关产品推荐
相关产品推荐

