没人警告你的 Webhook 故障模式
Source: Dev.to
请提供您想要翻译的完整文本内容,我将按照您的要求将其翻译成简体中文并保留原始的格式、Markdown 语法以及技术术语。谢谢!
概览
Webhook 集成看似简单:将 Stripe 指向你的端点,返回 200 OK,就完成了。然而在生产环境中,问题可能会悄然出现,让你猜测是负载、签名、服务器、Stripe 的重试队列,还是下游服务出了问题。
本实用指南涵盖了开发者最常遇到的 webhook 失败模式,并提供更快速的调试策略。
您的端点返回 200 OK 但处理程序从未触发
发生了什么?
- 服务器接受了请求,但负载被路由到应用程序的其他部分,且该部分静默失败。
- 中间件可能过滤了事件。
- 收到了 webhook,但数据库写入失败且错误被吞掉。
典型(慢)调试方法
- 在处理程序的各处插入
console.log()语句。 - 部署更改。
- 等待 Stripe 的重试计划(最长 78 小时)。
- 检查日志并重复上述步骤。
更快的方法
在请求到达您的应用程序之前捕获原始 webhook 请求。这样您可以准确看到 Stripe 发送了什么、您的端点返回了什么以及何时返回——无需修改代码。
API 版本不匹配
症状event.data.object 为 null 或空对象 ({})。
根本原因
您的端点使用的 Stripe API 版本与生成事件的版本不同。Stripe 不会发出警告;它仅以创建时的版本发送负载。
解决办法
在处理程序的最顶部记录原始请求体,在任何解析或中间件运行之前。
签名验证错误
常见场景
- 您在验证 Stripe 签名,但一直失败。
- 重新生成 webhook 密钥也没有帮助。
- 在测试时硬编码原始负载可以正常工作。
根本原因
验证的是 已解析 的请求体而不是 原始 请求体。Stripe 的签名是基于原始请求负载计算的,而不是基于已反序列化的 JSON 对象。
错误示例(Node/Express)
// Wrong — bodyParser already parsed the JSON
app.post('/webhook', (req, res) => {
const sig = req.headers['stripe-signature'];
stripe.webhooks.constructEvent(req.body, sig, secret); // req.body is PARSED
});正确示例
// Right — use the raw body
app.post(
'/webhook',
express.raw({ type: 'application/json' }),
(req, res) => {
const sig = req.headers['stripe-signature'];
stripe.webhooks.constructEvent(req.body, sig, secret); // req.body is RAW
}
);如果您花了一个小时追踪 Stripe 签名错误,很可能就是遇到了这个问题。
网络和基础设施问题
- 已过期的隧道 – ngrok 隧道可能已过期,导致 Stripe 的请求被切断。
- 防火墙阻拦 – 您的防火墙可能阻止了 Stripe 的 IP 段。
- 服务器宕机 – 进程在崩溃后可能未重新启动。
当 Stripe 报告投递失败时,意味着您的服务器从未收到该事件。由于无法看到公共可达性,您只能在 Stripe 通过电子邮件通知您投递失败后才发现问题。
在不等待重试的情况下测试修复
Stripe 的重试计划:
- 第一次失败后 1 小时
- 再过 12 小时
- 再过 72 小时
这意味着在确认修复在生产环境中有效之前,需要等待最长 78 小时。在开发阶段,这种延迟非常痛苦。
解决办法
使用 Stripe CLI 手动触发测试事件。这会模拟负载,但并不能完全复制生产环境的网络条件。
共同点:缺乏可见性
上述所有故障模式都有一个共同的问题:你无法看到 webhook 请求实际发生了什么。
Webhook 调试工具
在发送方(Stripe、GitHub 等)和你的服务器之间放置的专用调试端点提供三个关键功能:
- Capture – 发送方会访问调试端点,而不是直接请求你的服务器。
- Inspect – 在仪表盘中查看完整的原始负载、头信息、响应和时间信息。
- Replay – 立即将相同的负载重新发送到你的服务器,绕过 Stripe 的重试计划。
这种方式可以让你在几秒钟内捕获故障,而不是数小时,从而确保你的服务器准确收到发送的内容。
介绍 Hooklog
我创建 Hooklog 来解决这个问题。它免费(每月 10 k 事件),无需注册,并提供:
- 一个唯一的 webhook URL,您可以立即将任何服务指向它。
- 完整的负载检查:请求头、正文、响应、时延。
- 一键重放,测试您的处理程序,无需等待重试。
- 当您的端点返回 4xx 或 5xx 响应时发送电子邮件提醒。
开始使用:
- 免费层级: 每月 10,000 条事件,保留 3 天,最多 3 个端点。无需信用卡。
分享你的故事
你最糟糕的 webhook 调试经历是什么?在评论里告诉我——我会全部阅读。