什么是 Webhook?应用之间如何互相通知
Webhook 是一个自动消息,在某件事发生的那一刻,由一个服务发送到你的应用。当客户的付款成功时,Stripe 会向你应用中的某个地址发送一个 Webhook,内容是“付款成功,以下是详情”,然后你的应用做出反应:把订单标记为已付款、发送收据、解锁账户。简而言之,API 是你的应用向另一个服务提问;Webhook 则是另一个服务主动调用你的应用,告诉它一件事。
用 AI 建站时为什么它很重要
只要你的应用开始收款、接收其他工具提交的表单,或连接 GitHub、Shopify、日历等服务,你就会接触到 Webhook。它们通常是得知某件事已经发生的正确方式,但也是 AI 构建的应用最容易出现细微错误的地方:
- 端点接受任何请求,因此任何人都可以伪造“付款成功”的事件。
- 应用在结账跳转页面上授予访问权限,而不是依靠 Webhook,因此提前关闭标签页的人拿不到他们已付款的内容,而找到成功页面网址的人却能免费获得访问权。
- 同一事件到达两次,客户收到两个订单或两封邮件。
了解 Webhook 的工作方式,可以让你提前提出这些保护要求。
日常类比:送货短信
你可以用两种方式知道包裹是否已送达。你可以每隔十分钟走到门口去看一眼(这叫轮询,即你的应用反复调用 API 询问“有新情况吗?”)。或者快递员在送达后给你发一条短信(这就是 Webhook)。
短信显然更好,前提是你能信任它。如果任何人都能给你发一条“包裹已送达”的消息,你会希望有办法确认它真的来自快递员。而且如果你送信时手机没开机,你也希望快递员之后再试一次。这两点——验证和重试——基本就是 Webhook 变得棘手的原因。
Webhook 的工作步骤
- 你在应用的后端创建一个端点:一个接受
POST请求的网址,例如https://yourapp.com/webhooks/stripe。 - 你向服务商注册这个网址,并选择你想接收的事件(例如“结账完成”和“订阅已取消”)。
- 服务商会给你一个签名密钥。 你把它作为密钥存放在服务器上,参见环境变量和密钥。
- 事件发生。 服务商向你的网址发送一个 HTTP 请求,请求体是描述该事件的 JSON,并附带一个签名头。
- 你的应用验证签名,记录事件 ID,迅速返回成功代码(
200),然后再执行后续工作。 - 如果你的应用没有返回成功,许多服务商会稍后再次尝试。
签名
签名用于证明请求确实来自服务商,并且没有被篡改。例如,Stripe 会使用你的签名密钥,对请求体和时间戳计算一个 HMAC(一种带密钥的指纹,采用 SHA-256 算法),并把结果放在 Stripe-Signature 请求头中发送。你的应用用自己保存的密钥做同样的计算;如果结果一致,就说明请求是真实的。由于时间戳也参与了签名,你可以拒绝那些被人记录下来、之后又重放的旧请求——根据 Stripe 截至 2026 年 9 月的文档,其库默认的容差为五分钟。
一个实际细节:签名是基于原始请求体计算的。如果你的框架在验证之前就解析并重新格式化了 JSON,检查就会失败。这是一个非常常见的错误。
重试、重复与顺序
不同服务商的做法各不相同,请查阅各自的文档。截至 2026 年 9 月:
| 行为 | Stripe | GitHub |
|---|---|---|
| 自动重试 | 有,正式模式下最多三天,间隔逐渐拉长 | 没有;你需要手动或通过脚本重新投递失败的请求 |
| 响应时间 | 尽快返回 2xx,在任何慢速工作之前 | 如果超过 10 秒仍未响应,该次投递视为失败 |
Stripe 的文档还指出,事件不保证按发生的顺序到达,同一事件偶尔也可能到达多次,因此建议记录事件 ID。
这一普遍原则适用于任何服务商:事件可能迟到、重复到达,并且顺序错乱。你的处理程序应当是幂等的——对同一事件处理两次,与只处理一次的效果相同。
实例:解锁付费课程
你在销售一门在线课程。学生点击购买,在 Stripe 的托管结账页面付款,然后被带回你的网站。
脆弱的做法: “感谢”页面直接解锁课程。如果学生在跳转途中关闭了浏览器,他们已经付了款却没有访问权限。如果有人猜到了感谢页面的网址,他们就能不付款获得访问权限。
使用 Webhook 的做法:
- Stripe 确认付款后,会向
/webhooks/stripe发送一个checkout.session.completed事件。 - 你的后端用签名密钥验证签名。如果验证失败,就返回
400,不做任何处理。 - 它检查该事件 ID 是否已被处理过。如果是,就返回
200并停止。 - 它保存事件 ID,返回
200,然后为学生开通访问权限并发送欢迎邮件。 - 感谢页面只显示“已收到付款——您的课程将很快出现”,并检查学生的访问状态。
之后,如果订阅被取消或银行卡扣款失败,其他 Webhook 事件会告诉你的应用取消或暂停访问权限。这就是订阅类产品与计费系统保持同步的方式,参见什么是 SaaS和如何为应用添加支付功能。
关键术语
- 端点(Endpoint): 你应用中接收 Webhook 的网址。
- 事件 / 负载(Event / payload): 发生了什么,以及描述它的数据(通常是 JSON)。
- 签名密钥(Signing secret): 用于验证签名的共享密钥。
- 幂等(Idempotent): 重复执行多次,结果与执行一次相同,因而是安全的。
- 轮询(Polling): 反复向 API 询问变化,而不是等待 Webhook。
- 隧道(Tunnel): 一种工具,在开发期间为你的笔记本电脑提供一个临时的公网网址,使 Webhook 能够访问它。
常见错误与误解
- 不验证签名。 端点网址并不是秘密。验证才是让请求值得信任的原因。
- 在回复之前执行耗时操作。 在响应之前发送邮件或生成 PDF,可能导致超时,超时又会触发重试,重试进而造成重复。
- 假设事件恰好一次、按顺序到达。 应记录事件 ID,不要依赖到达顺序。
- 使用预览网址。 Webhook 需要稳定的公网地址。私有预览和
localhost无法从互联网访问;请使用你已发布的网址(或在测试时使用隧道)。 - 混用测试和正式密钥。 服务商通常为测试模式和正式模式签发不同的签名密钥。请同时保存两者,并使用正确的那一个。
- 对重要决策盲目信任负载。 对于高风险操作,在收到事件后,从服务商的 API 获取最新状态是合理的做法。
向你的 AI 建站工具提出什么要求
在服务器上添加一个
POST /webhooks/stripe端点。使用原始请求体和密钥STRIPE_WEBHOOK_SECRET验证 Stripe 签名。对无效签名返回 400。保存每个事件 ID,并跳过已处理过的事件。快速返回 200,然后处理checkout.session.completed:把订单标记为已付款并发送收据。记录事件类型。不要在结账成功页面上授予访问权限。
然后进行测试:从服务商后台发送一个测试事件,再发送同一个事件一次,以及一个签名错误的请求。只有第一次应当产生实际改动。
Mythex 中的 Webhook
Mythex 不运行单独的 Webhook 服务;你需要让 Agent 在你应用自己的后端中添加一个 Webhook 端点,并将服务商指向你的已发布网址,因为 Webhook 需要公网地址。签名密钥放入你的项目密钥中;如果你在线上应用中更改了它,就需要重新发布。文档中的处理 Webhook 方案提供了起始提示词,而店铺模板则是收款应用的良好起点。
常见问题
简单来说,什么是 Webhook?
Webhook 是一个自动消息,当某件事发生时(例如付款成功或表单被提交),一个服务会把它发送到你应用中的一个网址。你的应用不必反复询问是否有变化,而是由另一个服务主动告诉它。
Webhook 和 API 有什么区别?
使用 API 调用时,你的应用向另一个服务请求某些内容,并得到回应。使用 Webhook 时,另一个服务在事件发生时调用你的应用。许多集成会同时使用两者:用 Webhook 获知事件,用 API 调用获取详情或执行操作。
Webhook 安全吗?
只要你进行验证,就可以是安全的。设计良好的服务商会用一个只有你知道的密钥为每个 Webhook 签名,你的应用应拒绝任何签名不匹配的请求。如果没有这项检查,任何找到该网址的人都可以发送伪造的事件。
如果 Webhook 发送时我的应用宕机了,会怎样?
这取决于服务商。例如,Stripe 在正式模式下最多会在三天内对失败的投递进行重试,而 GitHub 不会自动重试,需要你重新投递。请查阅各服务商的文档,并设计你的处理程序,使其能够应对迟到或重复的事件。