在 ChannelDock 中设置 Webhooks
Last updated
为什么使用 webhook?
ChannelDock 提供 webhook,以便账户中发生变化时立即通知您的系统。无需按计划轮询 API,当创建或更新订单、创建发货、库存变化或登记退货时,您会自动收到通知。Webhook 有助于自动化流程并减少不必要的 API 请求。
主要特性
- 事件时机: Webhook 在事件发生后数分钟触发,提供近实时更新。
- 载荷一致性: webhook 的 JSON 载荷与对应 API 端点返回的结构一致。
- 自动重试: 如果 ChannelDock 无法投递 webhook,最多尝试五次,延迟递增(0、30、60、120 和 240 秒)。十次投递失败后,为安全起见会禁用该 webhook。
- 安全性: 每个 webhook 可以拥有各自的密钥。设置密钥后,ChannelDock 会在
X-Channeldock-Signature请求头中对每次投递附加 HMAC-SHA256 签名,您可据此验证请求确实来自 ChannelDock。
设置 webhook
-
前往设置: 登录 ChannelDock,打开 Settings → API & Webhooks。您会看到两个部分:API keys 和 Webhooks。
-
创建新 webhook: 点击 Create new webhook。将出现 “Webhook Configuration” 窗口。
-
填写字段:
- Webhook name: 选择描述性的内部名称(例如 “Order updates”)。
- Webhook URL: 输入 ChannelDock 可向其发送 HTTP POST 请求的端点 URL。确保该 URL 可从公网访问,并在 5 秒内响应。
- Event to trigger webhook: 选择要接收通知的事件类型。可能的事件包括
order.created、order.updated、order.status.changed、order.picking、order.picked、order.deleted、shipment.created、stock.updated、return.created、return.handled和return.product.updated。 - Status: 保持为 Active。十次投递失败后 webhook 会自动停用。
- Webhook 密钥(可选但推荐): 填写您自己的密钥,或点击 生成 创建一个强密钥。ChannelDock 使用该密钥对每次投递进行签名,您可据此验证请求来自 ChannelDock 且在传输途中未被篡改。
-
保存: 点击 Save webhook。ChannelDock 会保存您的 webhook,并将所选类型的事件发送到您的端点。
载荷结构与事件
所选事件发生时,ChannelDock 会向您的端点发送 JSON 载荷。载荷至少包含以下字段:
{
"event": "order.created",
"payload": {
...
},
"signature": "<hash>" (已弃用,见下文)
}
- event – 该 webhook 配置的事件(例如
order.created)。 - payload – 包含订单、发货、退货或库存变动的详细信息。其结构与对应对象的 API 响应一致。
- signature – 仅在配置了密钥时出现。这是旧签名,已弃用;请改为验证
X-Channeldock-Signature请求头。
验证签名
您的 webhook URL 必须可公开访问,而请求本身不携带任何其他发送方凭证——没有 API 密钥,也没有密码。因此,凡是能到达该 URL 的请求,在您的端点看来都像是真正的 ChannelDock 投递:可能是通过日志文件、代理或支持工单泄露的 URL,也可能是他人截获后重新发送的历史投递。若不加验证就处理内容,一条伪造的 stock.updated 可能把您的库存清零,一条伪造的 order.updated 可能在您自己的系统中把订单标记为已发货。
签名正是这份缺失的凭证。只有您和 ChannelDock 知道该密钥,因此只有你们双方才能生成与眼前这次投递相匹配的值。
设置 webhook 密钥后,该 webhook 的每次投递都会带上一个额外的 HTTP 请求头:
X-Channeldock-Signature: sha256=8b415f2c0cd241a21109e007942b6ce43cbfcf97f7b2d7829084258c0ae0a66f
该值是请求正文的 HMAC-SHA256 哈希,以您的密钥作为密钥计算得出。您在自己一侧计算同样的哈希,并检查两者是否完全相同。未设置密钥时,不会发送该请求头。
在应用中验证签名
- 读取原始正文。 在 JSON 被解析之前,以文本或字节形式取得请求正文。大多数框架会解析 JSON 并丢弃原始文本,因此请显式获取:PHP 用
php://input,Laravel 用$request->getContent(),Flask 用request.get_data(),Django 用request.body,Rails 用request.raw_post,Express 用express.json({ verify: (req, res, buf) => { req.rawBody = buf } })。 - 读取请求头。 取
X-Channeldock-Signature并去掉sha256=前缀。查找请求头时请忽略大小写——取决于连接方式,它可能以x-channeldock-signature的形式到达。 - 计算自己的哈希。 以您的 webhook 密钥为密钥,对原始正文计算 HMAC-SHA256,并以十六进制表示。在 PHP 中即
hash_hmac('sha256', $raw, $secret)。 - 比较,请使用
hash_equals等恒定时间函数。两者相同则投递为真,可以处理;否则返回 HTTP 401 并忽略正文。只有该步骤成功后才解析 JSON。
重要:请对您收到的正文原样计算哈希。 签名是对字节的哈希,而非对 JSON 含义的哈希。因此不要先解析 JSON 再转回文本去计算哈希。两种语言可以写出含义完全相同但文本并不相同的 JSON:PHP 把斜杠写成 c\/o,而 Node.js 和 Python 写成 c/o。它们解析回来是相同的数据,却会产生完全不同的哈希。也不要在计算哈希前移除 signature 字段——它属于被签名的正文。
已弃用的 signature 字段
在该请求头出现之前,ChannelDock 把 signature 字段放在正文里。该字段仍会原样发送,因此现有对接不会中断,但它已被弃用。要验证它,必须移除该字段,再把其余 JSON 完全按照 PHP 的写法重建为文本,包括 PHP 把 / 写成 \/ 的习惯。在其他语言中几乎无法做到完全一致。
新的对接请基于请求头开发。如果您目前验证的是该字段,也不会中断:两者在每次投递中都会发送,因此您可以在方便的时候切换。这两个值永远不会相同,因为它们覆盖的数据不同——切勿相互比较。
安全处理提示
- 为每个 webhook 分配各自的密钥,并定期轮换。
- 使用恒定时间比较函数(例如 PHP 的
hash_equals或 Node.js 的crypto.timingSafeEqual)以防止时序攻击。 - 在对载荷内容采取任何操作之前先验证签名。
- 在执行操作前对载荷内容做额外校验(例如确认订单存在)。
最佳实践
ChannelDock 建议以下做法,以便安全可靠地处理 webhook:
- HTTP 200 响应: 端点在成功接收载荷后尽快返回 HTTP 200 OK。否则 ChannelDock 会将该次尝试视为失败并重试。
- 幂等性: webhook 消息有时可能发送两次(例如因网络问题或重试)。确保处理逻辑幂等,以免重复消息导致重复工作。
- 监控: 使用 ChannelDock 仪表板监控 webhook 状态并识别错误。
- 载荷处理: 确保端点能处理较大载荷,并在**合理时间内(≤ 5 秒)**响应。十次投递失败后 webhook 会自动停用。
Was this helpful?