如何测试 Webhook:工具与分步指南

Webhook测试很棘手?本文为你梳理好用的测试工具箱,从数据捕获、本地隧道到服务商触发器,一步步教你如何端到端地调试和断言你的Webhook处理程序,轻松搞定异步与签名验证等难题。

用 Apifox,节省研发团队的每一分钟

如何测试 Webhook:工具与分步指南

免费使用 Apifox

相关推荐

最新文章

API

一体化协作平台

API 设计

API 文档

API 调试

自动化测试

API Mock

API Hub

立即体验 Apifox
目录

要测试 Webhook,你需要向服务提供商提供一个可访问的 URL,触发一个真实事件,然后确认你的处理程序(handler)接收了 payload 并做出正确的响应。难点在于,你的应用是接收方,而不是调用方,所以你无法直接点击“发送”并读取响应。本指南将介绍你所需的工具(检测服务、本地隧道、提供商触发器)以及一个可重复的流程,以端到端地断言你的处理程序。

为什么 Webhook 比普通 API 更难测试

对于普通的 API 调用,你可以控制请求。你选择方法、设置 body、发送请求并读取响应。Webhook 则相反。提供商会在其自己的时间安排下向你发送请求,且携带它定义的 payload。这种角色反转带来了四个测试问题。

首先,默认情况下你无法自己触发事件。payment_intent.succeeded 事件只有在 Stripe 决定发生时才会触发,因此你需要提供商的工具来强制触发一个事件。

其次,发送是异步的。事件会在上游操作完成时随时到达,因此你的测试必须捕获传入的请求,而不是阻塞等待返回值。

第三,payload 的格式是由提供商定义的。你的处理程序必须精确解析 GitHub、Stripe 或 Slack 发送的内容。

第四,大多数提供商都会对其请求进行签名。你的接口在信任 body 之前必须验证签名 header,如果测试跳过了这一步,就会隐藏真正的 Bug。如需深入了解,请参阅我们的 Webhook 签名验证指南。

如果你仍在决定 Webhook 是否是适合你集成的模式,“Webhook 对比轮询”以及“Webhook 对比 WebSocket”的文章对比了它们之间的权衡。

Webhook 测试工具箱

你通常会在同一个调试过程中用到四种工具:用于查看原始 payload 的捕获服务、用于连接到你笔记本电脑的隧道、用于触发真实事件的提供商触发器,以及用于验证处理程序的断言工具。

1. 检测与捕获服务

在编写任何处理程序代码之前,将提供商指向一个临时的 URL,并查看它实际发送的内容。这些服务会为你提供一个公开的接口,并实时显示每个请求。

webhook.site 在页面加载的瞬间就会为你提供一个唯一的随机 URL 和电子邮件地址。发送给它的所有内容都会立即显示:完整的 body、headers 和方法。免费的 URL 会在 7 天后过期,且上限为 100 个请求,最大请求大小为 10 MB。付费计划则增加了永久 URL、无限请求以及保留最新 10,000 条请求历史的功能。

Beeceptor 提供了一个免费的 HTTPS 接口,你可以将其用作 Webhook 接收器并实时检测传入的 payload。它还提供 mock 服务器接口,因此你可以通过同一个工具进行捕获和模拟。

Pipedream RequestBin 是另一个广泛使用的请求捕获工具。请查看其当前的文档以获取具体的方案分级,因为捕获服务经常会更改其免费额度限制。

使用这些来回答一个问题:真实的 payload 是什么样的?复制一个样本以备后用,以便日后构建可重复的测试。

2. 本地开发:使用隧道暴露 localhost

提供商无法访问你机器上的 localhost:3000。隧道会创建一个公开的 HTTPS URL,将流量转发到你的本地端口,这样你就可以在编辑器中运行处理程序并进行实时调试。

ngrok 是常用的选择。安装它,进行一次身份验证,然后转发端口。

brew install ngrok                          # macOS
ngrok config add-authtoken $YOUR_TOKEN
ngrok http 3000                             # forwards a public HTTPS URL to localhost:3000

免费的 ngrok 账号会获得一个自动分配的开发域名。自定义域名则需要付费计划。

cloudflared 如果你更倾向于使用 Cloudflare,只需一条命令即可快速运行隧道。

cloudflared tunnel --url http://localhost:3000

将隧道输出的公开 URL 粘贴到提供商的 webhook 设置中,传入的事件就会到达你的本地服务端。若要了解此模式的更详细步骤,请参阅如何使用 webhook 服务测试本地 API。

3. 从提供商触发测试事件

只有向捕获 URL 发送数据时,它才起作用。大多数主流提供商都提供了按需触发测试事件的工具,因此你无需制造真实的支付或推送。

Stripe CLI 是最简洁的例子。stripe listen 命令将实时事件从你的 Stripe 沙箱转发到本地路径,并输出一个你需放入应用配置中的 webhook 签名密钥。

# Forward all events to your local handler:
stripe listen --forward-to localhost:3000/webhooks

# Filter to specific events only:
stripe listen --events payment_intent.succeeded,checkout.session.completed \
  --forward-to localhost:3000/webhooks

在监听器运行的情况下,stripe trigger 会触发一个测试事件。请注意,触发操作会创建具有实际底层支持的 API 对象并产生副作用:例如,payment_intent.succeeded 也会触发 payment_intent.created

stripe trigger payment_intent.succeeded
stripe trigger checkout.session.completed
stripe trigger --help                       # list every supported event

GitHub 保留了简短的投递历史记录供你重放。进入你的仓库,然后依次点击 “Settings(设置)”、在 “Code and automation” 下的 “Webhooks”。点击 webhook URL,打开 “Recent deliveries(最近投递)” 选项卡,点击一个投递的 GUID,然后点击 “Redeliver(重新投递)”。有两点限制需要注意:你只能重新投递过去 3 天内的记录,并且你需要对该仓库拥有管理员权限。GitHub 不会自动重新投递失败的记录,因此重放是手动进行的。

Slack 的传入 webhook 最容易测试。你只需向 webhook URL 发送一个 POST 请求,并携带 JSON 数据即可发送消息。最简 payload 仅包含一个 text 字段。

curl -X POST https://hooks.slack.com/services/T00000000/B00000000/XXXXXXXXXXXXXXXXXXXXXXXX \
  -H 'Content-type: application/json' \
  -d '{"text":"Hello, world."}'


Slack webhook URL 属于机密信息。Slack 会注销泄露的 URL,因此请不要将其放在客户端代码和公开仓库中。

4. 断言你的处理器

捕获和触发只能证明链路是通的,并不能证明你的处理器是正确的。最后的步骤是发送精心构建的 payload,并检查响应以及副作用。最基本的方法是使用带有代表性 body 的 curl 命令。

curl -X POST http://localhost:3000/webhooks \ -H 'Content-Type: application/json' \ -H 'Stripe-Signature: t=…,v1=…' \ -d '{"id":"evttest","type":"paymentintent.succeeded","data":{"object":{"id":"pi_123","status":"succeeded"}}}'

单个 curl 命令对于冒烟测试来说已经足够了。但如果你想在 CI 中运行可重复且带断言的测试,它就显得力不从心了。而这正是专用 API 工具的用武之地。

使用 Apifox 测试 Webhook

Apifox 是一款集 API 设计、调试、测试、mock 和文档于一体的全功能 API 平台。它虽然没有专门的“webhook 收件箱”,但本节将实事求是地介绍它所擅长的事情:构建 payload、保存 payload、断言响应以及通过 mock 服务端来替代第三方服务商。

构建并保存示例 payload 作为可复用的请求

将你从 webhook.site 捕获(或从服务商文档中复制)的 payload 构建为 Apifox 请求。将请求方法设置为 POST,粘贴 JSON body,并添加服务商发送的 headers,包括你的处理器需要校验的签名 header。

将该请求保存到对应的接口。现在,你就有了一种可重复、版本受控的方式来向处理器 POST 一个已知正常的(或故意构造错误的)payload,而无需每次都重新输入 curl 命令。

使用可视化断言生成器断言响应

发送 payload 只是测试的一半,另一半则是检查你的处理器返回了什么。在请求或场景步骤中,打开后置操作,点击“+ 添加”,然后选择“断言”。Apifox 将添加一个无需代码即可配置的校验规则。

将断言指向响应 body,并使用 $ 代表 JSON 根节点。例如,定位到 $.data.status,将条件设置为“等于”,并与 succeeded 进行比对。运行请求后,结果将显示在“断言”标签页中。可视化断言是将值作为字符串进行比较的。当你需要进行类型精确的检查(如实数、布尔值)时,可以切换到使用兼容 Postman 的 pm.test 语法的自定义脚本。

这就把“返回了 200”变成了“返回了 200,且 status 字段为 succeeded,且 order id 匹配”。你可以将多个断言构建到一个场景中,以覆盖成功路径、缺失字段的用例以及签名错误的拒绝情况。

使用 mock 服务端来替代第三方服务商

有时你可能想测试相反的方向:你技术栈中的某个服务需要调用第三方服务商。在本地测试期间,你可能根本不想请求真实的服务商。此时,Apifox 的 mock 服务端就可以用来替代它。

Apifox 提供了三种 mock 类型。本地 mock 随桌面客户端运行,且仅在客户端打开时有效。云端 mock 托管在 Apifox 服务端,24/7 全天候运行,支持开启或关闭(默认关闭)。Runner mock 运行在自托管的 runner 基础设施上,并在你的团队中共享。每个 HTTP 接口都有一个 mock 模块;可在文档模式下的 API 标签页或调试模式下的 mock 标签页中复制 mock URL。只有以 / 开头的路径才会路由到 mock 环境。在测试期间,将你的代码指向该 mock URL,你的集成即可获得可预测的服务商响应,而无需进行真实的 API 调用或产生副作用。

使用 Apifox CLI 在 CI 中运行 webhook 测试

一旦你的测试场景在本地通过,就可以在每次推送时使用 Apifox CLI 运行它。这需要 Node.js v16 或更高版本。

npm install -g apifox-cli node -v && apifox -v && which node && which npm && which apifox # verify install

在线运行已保存的测试场景,并传入测试场景 CI/CD“命令行”标签页中的访问令牌和相关 ID。

apifox run --access-token $APIFOXACCESSTOKEN -t 637132 -e 358171 -d 3497013 -r html,cli 

这里 -t 表示测试场景,-e 表示环境(必填),-d 表示测试数据(CSV 或 JSON 文件路径,或者已存储的数据集 ID),-r 设置报告格式(支持 clihtmljsonjunit)。有关完整的命令行演示,请参阅 Apifox CLI 教程。

想要以可视化方式构建和断言你自己的 webhook 测试吗?免费试用 Apifox,无需信用卡。

Webhook 测试的逐步工作流

结合这些工具,以下是一个可重复的执行顺序。

  1. 检查真实载荷。 将服务商指向 webhook.site URL 并捕获一个真实事件。记录 body 结构、headers 和签名格式。
  2. 连通你的代码。 在本地启动你的处理器(handler),使用 ngrok http 3000cloudflared 打开一条通道,并将公网 URL 填入服务商的 webhook 配置中。
  3. 触发真实事件。 使用 stripe trigger、GitHub 的 Redeliver 按钮或 Slack POST,通过通道发送一个真实的事件。
  4. 验证签名处理。 发送带有有效签名的相同载荷,然后再发送一个被篡改过的载荷。你的处理器必须接受前者并拒绝后者。
  5. 断言响应和副作用。 将载荷保存为 Apifox 请求,对响应 body 和状态添加断言,并确认数据库记录已更新或下游调用已触发。
  6. 自动化。 将该测试场景移至 Apifox CLI 中,以便在每次代码变更时自动在 CI 中运行。

如果你是在设计 webhook 系统本身,而不仅仅是使用它,那么“如何设计可靠的 webhook”和“支付 webhook 最佳实践”涵盖了重试、幂等性和安全性。对于更广泛的图景,“webhook API 指南”以及“webhook 与事件驱动架构”解释了 webhook 在更大系统中的位置。

常见问题

如何测试 webhook?

向提供商提供一个可访问的 URL,触发一个真实或测试事件,然后确认你的处理程序(handler)接收到了 payload、验证了签名、返回了正确的状态,并执行了预期的副作用。先捕获一个真实的 payload,然后使用断言构建一个可重复的请求,以确保每次测试运行的结果都一致。

如何在本地测试 webhook?

在本地端口上运行你的处理程序,然后通过隧道将其暴露出去,以便提供商可以访问你的机器。使用 ngrok http 3000cloudflared tunnel --url http://localhost:3000,将公开的 HTTPS URL 粘贴到提供商的 webhook 设置中,并触发一个事件。传入的请求会到达你的本地服务端,你可以在那里设置断点并进行实时检查。

如何使用 Postman 测试 webhook?

Postman 可以向你的接口发送一个精心构建的 POST payload 并断言其响应,但它本身无法直接接收真实的传入 webhook。Apifox 也是如此:你使用提供商的 payload 和 header 构建一个请求,在响应 body 和状态上添加断言,并将其保存为可重复使用的测试。要捕获真实的传入事件,需要将该工具与捕获服务或隧道结合使用。

如何测试 Stripe webhook?

使用 Stripe CLI。运行 stripe listen --forward-to localhost:3000/webhooks 将沙箱事件转发到你的处理程序并获取签名密钥。然后运行 stripe trigger payment_intent.succeeded(或 stripe trigger --help 中的任何其他事件)来触发一个真实的测试事件。触发操作会创建后端 API 对象并可能产生级联效应,因此 payment_intent.succeeded 也会触发 payment_intent.created

如何测试 Slack webhook?

向传入的 webhook URL 发送 POST JSON 请求。最小的有效 payload 是 {"text":"Hello, world."},并带有 Content-type: application/json header。测试成功后会将消息发布到配置的频道中。请确保该 URL 的私密性,因为 Slack 会撤销泄露的 webhook URL。

如何测试 webhook URL?

向该 URL 发送一个示例 POST 请求,并确认它返回成功状态且行为正确。最快的检查方法是使用单个包含代表性 body 的 curl 命令。对于真实的测试,请先捕获实际的 payload,分别使用有效和无效的签名发送它,并断言其响应和副作用,而不仅仅是检查是否返回 200 状态码。

开发必备:API 全流程管理神器 Apifox

介绍完上文的内容,我想额外介绍一个对开发者同样重要的效率工具 —— Apifox。作为一个集 API 文档、调试、设计、测试、Mock、自动化测试于一体的工具,Apifox 是目前提升研发效率的首选。

如果你正在开发项目,不妨试试其极其友好的界面设计,它完全兼容 Postman 和 Swagger 数据格式,导入数据非常方便,,即使是新手也能很快上手,点击这里即可注册使用

Apifox

值得一提的是,除了个人和常规团队使用,针对有高安全合规要求、或需要在内网环境协作的企业,Apifox 还提供了深度定制的私有化部署方案

获取专属报价与部署方案

icon 详细的私有化部署系统架构与安全白皮书
icon 针对您公司规模的专属报价单
icon 免费的 1v1 专属产品演示 (Demo) 机会
获取部署方案
* 提交后,我们的客户经理将在 1 个工作日内与您联系
林俊锋 企业微信
@Apifox 专属顾问
扫码备注: 私有化 + 公司名