首先完成“第4课:在服务之间转换和路由数据”即可解锁本课程。转到上一课

什么是 Webhook 以及它为何重要

大多数 API 集成都是基于拉取的模式:你的工作流按计划运行,调用外部服务,获取自上次检查以来的所有变更。Webhook 反转了这一模式。不是你去询问,而是外部服务在事件发生的瞬间将数据推送给你 —— 支付完成、表单提交、代码仓库收到新的提交。其结果是近乎即时的响应,且完全没有轮询开销。

n8n 内置的 Webhook 节点可以将任何工作流转变为一个 HTTP 端点。当该端点收到请求时,工作流会立即触发。本课将逐步讲解如何进行设置、处理传入的负载,以及向调用方返回正确的响应。

流程图,对比轮询模式(n8n 反复调用 API)与 Webhook 模式(API 在事件发生时一次性调用 n8n)

设置 Webhook 节点

将 Webhook 节点拖到画布上,并将其设置为触发器(第一个节点)。你需要立即配置的两项设置是 HTTP 方法和路径。

HTTP 方法几乎总是 POST —— 这是所有主流平台发送的方式。仅当第三方明确文档说明时才使用 GET(某些验证握手使用 GET)。

路径(Path)是标识此工作流的唯一短标识。n8n 默认生成一个 UUID,但你可以设置一个易读的名称,例如 /stripe-events 或 /github-push。n8n 向你展示的完整 URL 如下所示:

bash
https://your-n8n-instance.com/webhook/stripe-events

你将该 URL 粘贴到第三方平台的 Webhook 设置中 —— Stripe 控制台、GitHub 仓库设置、Typeform,或是任何其他服务。

n8n 为每个节点提供两个 Webhook URL:测试 URL 和生产 URL。测试 URL 仅在你处于编辑器中且工作流打开并处于监听状态时才有效。生产 URL 仅在工作流已保存并已激活时才有效。永远不要将你的测试 URL 提供给供应商用于正式集成 —— 一旦你关闭浏览器标签页,它就会停止工作。

接收并解析负载

Webhook 触发后,传入的数据会进入 Webhook 节点的输出。n8n 会自动解析 JSON 请求体,因此如果 Stripe 发送 payment_intent.succeeded 事件,你可以在后续节点中直接通过表达式访问支付金额:

javascript
{{ $json.data.object.amount }}

对于表单编码的请求体(一些较老的服务发送 Content-Type: application/x-www-form-urlencoded),n8n 也会自动将其解析到同一个 $json 对象中。

请求头也可以获取,这对于签名验证很重要。Stripe、GitHub 以及大多数正规平台会使用 HMAC 密钥对其 Webhook 负载进行签名,以便你可以确认该请求确实来自它们。在 n8n 中,你可以在 Code 节点内读取签名请求头并进行验证:

javascript
const crypto = require('crypto');
const secret = 'your_webhook_secret';
const payload = $input.first().binary?.data
? Buffer.from($input.first().binary.data, 'base64').toString()
: JSON.stringify($input.first().json);
const signature = $input.first().headers['x-hub-signature-256'];
const expected = 'sha256=' + crypto
.createHmac('sha256', secret)
.update(payload)
.digest('hex');
if (signature !== expected) {
throw new Error('Invalid webhook signature');
}
return $input.all();

对于会触发任何敏感操作(发送邮件、修改记录、对用户扣款)的生产环境工作流,务必验证签名。

示意图:Webhook 节点接收请求,传递给签名校验的 Code 节点,然后分支到处理节点或错误节点

向调用方返回响应

某些平台要求返回特定的 HTTP 响应,而不仅仅是默认的 200 OK。Stripe 期望在几秒内收到 200 响应,否则会进行重试。GitHub 期望返回 200。一些系统(如 Typeform 或自定义内部服务)希望返回 JSON 响应体以确认接收。

在 Webhook 节点设置中,将响应模式(Response Mode)设置为 Last Node(最后一个节点)。现在,工作流中的最后一个节点将控制返回给调用方的内容。将其与位于链路末尾的 Respond to Webhook 节点配合使用并进行配置:

json
{
"statusCode": 200,
"body": { "received": true, "id": "={{ $json.id }}" }
}

如果你的工作流需要执行繁重的处理 —— 数据库写入、发送邮件、调用其他 API —— 同时仍需要快速响应,请在 Webhook 节点中使用 Response Mode: Immediately(立即响应)。n8n 会立即返回 200,并在后台继续运行工作流的其余部分。其代价是你无法发送动态的响应体,但调用方永远不会超时。

需要避免的常见错误

在生产环境中使用测试 URL 是最常见的错误。一旦你关闭编辑器,工作流就会静默停止,直到事件丢失后才会有人注意到。

未处理重试是另一个常见漏洞。Stripe 会重试失败的 Webhook 长达 72 小时。如果你的工作流不具有幂等性 —— 即对同一事件运行两次会导致重复记录或重复扣款 —— 则你需要在执行任何写入操作之前检查是否已处理过给定的事件 ID。

忽略响应超时会导致静默失败。如果你的工作流耗时 30 秒,而调用方期望 5 秒内收到响应,它会将该投递标记为失败并进行重试,即使你的工作流最终成功完成。要么立即响应,要么优化处理路径。

小结

Webhook 让第三方服务实时向 n8n 推送事件,无需再进行定时轮询。你需要使用路径和 HTTP 方法设置一个 Webhook 节点,将生产 URL 粘贴到供应商的设置中,然后通过下游节点中的 $json 访问负载。签名验证可以防止伪造请求,而 Respond to Webhook 节点或立即响应模式让你可以控制返回给调用方的内容。处理好这些细节 —— 正确的 URL、签名校验、幂等性、响应时机 —— 正是将脆弱的集成与在生产环境中可靠运行的集成区分开的关键。

课后练习

课程检查点

巩固所学知识,获取作业反馈。

0/7
01Webhook 集成与轮询集成之间的关键架构区别是什么?
02在 n8n 中,应当在什么情况下使用生产环境 Webhook URL 而不是测试 URL?
03第三方服务以 Content-Type: application/x-www-form-urlencoded 发送了一个 Webhook。n8n 如何处理该负载?
04对传入的 Webhook 请求进行 HMAC 签名验证的目的是什么?
05你需要向调用方返回一个包含传入负载中某个字段的自定义 JSON 响应体。应该使用哪种 Webhook 节点响应模式?
06你的工作流在收到 Webhook 后需要执行多个耗时的数据库写入操作,而调用方服务在 5 秒后就会超时。为了防止调用方将投递标记为失败,最佳的响应模式是什么?
07由于你的端点第一次返回了错误,Stripe 重试了一次 Webhook 事件。而你的工作流并不具有幂等性。可能的后果是什么?
已回答 · 0/7