WooCommerce 如何投递 Webhook

WooCommerce 的投递依赖跑在 WP-Cron 上的 Action Scheduler,所以要等有页面加载时才发出。连续失败超过五次,Webhook 就会被停用。附签名格式和 Node 验证器。

投递行为

取自该平台的官方文档,最近核对于 2026-08-06。平台没有给出数字的地方,这张表也不填。

响应时限平台未公布

投递先进入 Action Scheduler 队列,由 WP-Cron 驱动,所以要等下一次有页面加载时才发出,而不是在事件发生时发出

重试平台未公布
放弃连续投递失败超过五次后,Webhook 会被停用
出处https://woocommerce.com/document/webhooks/

签名

用一个经测试套件证明的可运行验证器核对,不是照着文档读来的。最近核对于 2026-08-20。

算法HMAC-SHA256
待签名串raw body
编码base64
请求头x-wc-webhook-signature
时间容差无强制要求

验证签名

要用原始请求体,逐字节一致,并且在任何 JSON 解析之前。框架一旦重新序列化请求体,本页的每一种方案都会失效。

const crypto = require("node:crypto");

// base64(HMAC-SHA256(secret, raw body))
const expected = crypto
  .createHmac("sha256", webhookSecret)
  .update(rawBody)
  .digest("base64");
const received = Buffer.from(req.headers["x-wc-webhook-signature"] ?? "");
const wanted = Buffer.from(expected);
// timingSafeEqual throws on a length mismatch, so check that first.
const valid =
  received.length === wanted.length && crypto.timingSafeEqual(received, wanted);

容易踩的坑

下单时 Webhook 并不会触发。投递先排进 Action Scheduler,Action Scheduler 跑在 WP-Cron 上,而 WP-Cron 要等下一次有人加载页面才运行。在访问量小的店铺里,第一个字节发出之前就自带几分钟的延迟。

连续投递失败超过五次,Webhook 就会被直接停用,而店主往往要等到下游的数据明显过时了才发现。

延伸阅读

AnyHook 挡在接收 WooCommerce Webhook 的端点前面:约 1 秒应答,你的服务器宕机时按自己的计划重试,并且每个事件都可以重放。 只改一个 URL,代码不用动。

工作原理 →