没人警告你的 Webhook 故障模式

发布: (2026年3月28日 GMT+8 05:09)
7 分钟阅读
原文: Dev.to

Source: Dev.to

请提供您想要翻译的完整文本内容,我将按照您的要求将其翻译成简体中文并保留原始的格式、Markdown 语法以及技术术语。谢谢!

概览

Webhook 集成看似简单:将 Stripe 指向你的端点,返回 200 OK,就完成了。然而在生产环境中,问题可能会悄然出现,让你猜测是负载、签名、服务器、Stripe 的重试队列,还是下游服务出了问题。

本实用指南涵盖了开发者最常遇到的 webhook 失败模式,并提供更快速的调试策略。

您的端点返回 200 OK 但处理程序从未触发

发生了什么?

  • 服务器接受了请求,但负载被路由到应用程序的其他部分,且该部分静默失败。
  • 中间件可能过滤了事件。
  • 收到了 webhook,但数据库写入失败且错误被吞掉。

典型(慢)调试方法

  1. 在处理程序的各处插入 console.log() 语句。
  2. 部署更改。
  3. 等待 Stripe 的重试计划(最长 78 小时)。
  4. 检查日志并重复上述步骤。

更快的方法

在请求到达您的应用程序之前捕获原始 webhook 请求。这样您可以准确看到 Stripe 发送了什么、您的端点返回了什么以及何时返回——无需修改代码。

API 版本不匹配

症状
event.data.objectnull 或空对象 ({})。

根本原因
您的端点使用的 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 等)和你的服务器之间放置的专用调试端点提供三个关键功能:

  1. Capture – 发送方会访问调试端点,而不是直接请求你的服务器。
  2. Inspect – 在仪表盘中查看完整的原始负载、头信息、响应和时间信息。
  3. Replay – 立即将相同的负载重新发送到你的服务器,绕过 Stripe 的重试计划。

这种方式可以让你在几秒钟内捕获故障,而不是数小时,从而确保你的服务器准确收到发送的内容。

介绍 Hooklog

我创建 Hooklog 来解决这个问题。它免费(每月 10 k 事件),无需注册,并提供:

  • 一个唯一的 webhook URL,您可以立即将任何服务指向它。
  • 完整的负载检查:请求头、正文、响应、时延。
  • 一键重放,测试您的处理程序,无需等待重试。
  • 当您的端点返回 4xx 或 5xx 响应时发送电子邮件提醒。

开始使用:

  • 免费层级: 每月 10,000 条事件,保留 3 天,最多 3 个端点。无需信用卡。

分享你的故事

你最糟糕的 webhook 调试经历是什么?在评论里告诉我——我会全部阅读。

0 浏览
Back to Blog

相关文章

阅读更多 »

MCP的七宗罪:运营罪

操作罪:懒惰与愤怒 这些罪行属于此类别,因为它们决定了实时 MCP 系统在压力下的行为方式:它是否真实地失败……

忽视代码可维护性的痛苦

我最近花了好几个小时调试代码库中一个特别棘手的问题,当时我为了赶紧的截止日期而偷工减料。本该是一个简单的修复,却……