所有文章
电子商务订单和产品事件离开 WordPress 商店并穿过签名隧道到达本地主机 Webhook 处理程序。
WooCommerceWordPresse-commerce webhookslocalhost

在本地主机上测试 WooCommerce Webhooks

要在本地主机上测试 WooCommerce Webhook,请使用 HTTPS 隧道公开本地处理程序,在 WooCommerce → 设置 → 高级 → Webhooks 下创建一个 Webhook,然后验证 X-WC-Webhook-Signature 作为原始主体的 Base64 HMAC-SHA256 摘要。 在安全的测试商店中触发订单或产品更改、检查交付情况并进行迭代,而无需部署接收器。

WooCommerce 发送的内容以及发送时间

当创建、更新或删除订单、产品、优惠券或客户时,WooCommerce 可以通知交付 URL。扩展可以添加主题,开发者可以定义自定义主题。每个配置的 Webhook 都有名称、状态、主题、交付 URL、机密和 API 版本。这 官方 WooCommerce webhook 文档 描述创建、主题、交付日志和失败行为。

Webhook 附加到主题,而不是自动附加到每个存储突变。选择您的集成所需的最狭窄的主题。创建订单的消费者不应该同时处理每个产品更新。这可以减少本地测试期间的个人数据暴露、流量和意外副作用。

创建原始 Express 端点

WooCommerce 的签名是根据其发送的正文计算的。保留这些字节直到验证完成。签名标头包含 Base64 编码的二进制 HMAC-SHA256 摘要,而不是十六进制字符串。

import express from 'express';
import crypto from 'node:crypto';

const app = express();

function validWooSignature(rawBody, supplied, secret) {
  if (!supplied || !secret) return false;
  const expected = crypto
    .createHmac('sha256', secret)
    .update(rawBody)
    .digest('base64');
  const a = Buffer.from(supplied);
  const b = Buffer.from(expected);
  return a.length === b.length && crypto.timingSafeEqual(a, b);
}

app.post(
  '/webhooks/woocommerce',
  express.raw({ type: 'application/json', limit: '2mb' }),
  async (req, res) => {
    const supplied = req.get('x-wc-webhook-signature');
    if (!validWooSignature(req.body, supplied, process.env.WC_WEBHOOK_SECRET)) {
      return res.sendStatus(401);
    }

    const payload = JSON.parse(req.body.toString('utf8'));
    await webhookInbox.insertOnce({
      deliveryId: req.get('x-wc-webhook-delivery-id'),
      topic: req.get('x-wc-webhook-topic'),
      payload,
    });
    return res.sendStatus(202);
  },
);

app.use(express.json());
app.listen(3000);

特定于路由的原始解析器必须在全局 JSON 解析器之前运行。如果中间件首先解析主体,则重新字符串化对象可能会更改空格或转义并使摘要无效。这与以下内容中涵盖的原始主体规则相同 Webhook 签名指南,但 WooCommerce 专门使用 Base64 输出。

启动 HTTPS 隧道

  1. 启动您的接收器并确认其正在收听 http://localhost:3000
  2. 跑步 npx portpreview 3000 在第二个航站楼。
  3. 复制公共 HTTPS URL 并附加 /webhooks/woocommerce
  4. 在 WordPress 发送初始 ping 和主题传递时保持进程运行。

WordPress 主机(而不是您打开 wp-admin 的浏览器)必须能够访问公共 URL。隧道将公共请求与您的私人开发流程联系起来。它还提供受信任的 TLS,因此您无需公开路由器端口或安装自己的公共证书。

在 WooCommerce 中配置 Webhook

  1. 打开 WooCommerce → 设置 → 高级 → Webhooks
  2. 选择 添加网络钩子 并给它一个可识​​别的本地开发名称。
  3. 选择 积极的 状态和特定主题,例如已创建订单。
  4. 粘贴完整的隧道传送 URL。
  5. 生成一个长随机秘密并将相同的值放入 WC_WEBHOOK_SECRET
  6. 保存 Webhook,然后在测试存储中触发主题。

首次保存活动 Webhook 时,WooCommerce 会向交付 URL 发送 ping。 ping 确认连接,但不能替代真实订单有效负载。让您的端点容忍初始请求,然后创建或更新测试数据以练习所选主题。

export WC_WEBHOOK_SECRET="$(openssl rand -base64 48)"

如果将 Base64 机密粘贴到环境文件中,请引用它,以便保留标点符号。秘密是 HMAC 密钥; WooCommerce REST API 使用者密钥和 WordPress 密码是不相关的凭据。

使用标题来路由和跟踪交付

WooCommerce 包含有用的元数据标头。根据版本和环境,这些包括主题、资源、事件、源、Webhook ID 和交付 ID。按照 HTTP 的要求,不区分大小写地处理名称。使用主题进行调度,使用交付 ID 进行追踪,但始终首先对正文进行身份验证。

const handlers = {
  'order.created': handleOrderCreated,
  'order.updated': handleOrderUpdated,
  'product.updated': handleProductUpdated,
};

const handler = handlers[topic];
if (handler) await handler(payload);
else await recordUnsupportedTopic(topic);

不要仅从 JSON 形状推断主题。创建的订单和更新的订单有效负载可能看起来相似,但正确的下游操作不同。相反,拒绝您的端点从未配置为接受的标头/主题组合。

防御性地处理订单有效负载

使用不可变标识符

按商店标识和 WooCommerce 对象 ID(而不是订单号格式、客户电子邮件或显示名称)关联记录。两个商店都可以具有订单 ID 42,因此多商店集成需要复合键。

期望扩展改变字段

付款、订阅、税务、结帐和履行扩展可以添加元数据和行项目字段。验证业务逻辑所需的字段,忽略未知字段,并保存架构版本或最小编辑的固定装置以进行回归测试。

将事件接收与履行分开

表示订单已更改的 Webhook 应进入持久队列或收件箱。库存同步、运输标签、ERP 呼叫和客户电子邮件应在确认后运行。这可以防止缓慢的依赖关系使 WooCommerce 将成功的接收解释为失败的交付。

模型随着状态转换而更新

订单可能会经历待处理、处理中、暂停、已完成、取消、退款或失败状态。更新可能会很快发生,并且交付顺序并不能安全地替代比较时间戳和当前源状态。让重复的转换变得无害。

商业事件必须具有幂等性

在您的接收者提交之后、WooCommerce 看到响应之前,可能会发生超时。然后,重新传递会产生相同的业务操作,除非处理程序是幂等的。存储交付 ID(如果存在)。还强制执行域级别的唯一性,例如每个商店和订单转换一个履行请求。

await db.transaction(async (tx) => {
  if (!(await tx.deliveries.claim(deliveryId))) return;
  await tx.orders.applyWooCommerceEvent(storeId, topic, payload);
  await tx.outbox.enqueueRequiredActions(storeId, topic, payload.id);
});

收件箱加发件箱事务可以防止重复处理和丢失后续工作。看 webhook 重试和幂等性 以获得完整的图案。

使用 WooCommerce 日志调试发送方

WooCommerce 记录 Webhook 交付。打开 WooCommerce → 状态 → 日志 并过滤官方文档中描述的 webhook 传递源。将传送 URL、请求时间、响应状态和响应正文与本地隧道跟踪进行比较。发件人日志回答 WordPress 是否尝试了该请求;接收器日志回答您的应用程序用它做了什么。

请勿将未编辑的订单有效负载复制到公共问题中。它可以包含姓名、帐单和送货地址、电子邮件、电话、产品选择和付款元数据。将固定装置减少到重现错误所需的字段。

排查常见的 WooCommerce Webhook 故障

Webhook 被禁用

在连续五次以上的交付失败后,WooCommerce 会自动禁用 Webhook。根据官方指南,2xx、301 或 302 之外的响应将被视为失败。修复端点、重新激活 webhook 并发送受控测试。无论如何都要避免重定向:它们会使签名调试变得复杂,并且可能会意外地将签名的客户数据发送到非预期的主机。

签名总是不同的

使用 Webhook 配置的密钥对确切的原始正文进行哈希处理,请求二进制 HMAC 输出,然后对其进行 Base64 编码。在节点中,即 .digest('base64')。常见错误是使用十六进制、使用 REST API 密钥、首先解析 JSON 或包含额外的换行字节。

初始 ping 有效,但订单事件无效

确认所选主题与您触发的操作匹配。创建订单和更改现有订单是不同的主题。验证状态为“活动”,检查 WooCommerce 日志,并确保插件或临时缓存不会阻止底层挂钩。

本地请求返回404

检查全路径、路由方式、隧道目标端口。 WordPress 必须发布到 /webhooks/woocommerce,不仅仅是隧道起源。框架中间件不应将 Webhook 重定向到本地化或经过身份验证的页面。

交货超时

保留已验证的事件并立即返回200或202。将远程 API 调用和繁重的转换转移给工作人员。检查本地断点是否暂停请求足够长的时间以将其分类为失败。

重放有效负载会导致 401

捕获的请求必须保留准确的原始字节和签名标头。编辑 JSON 会使原始签名失效。对于业务逻辑测试,在验证边界后使用经过净化的夹具;对于端到端测试,生成具有专用测试密钥的新 HMAC。遵循 安全重播工作流程

本地商店数据的安全检查表

  • 尽可能使用合成客户和产品在临时商店进行测试。
  • 使用独特的 webhook 秘密进行本地开发,并在暴露后轮换它。
  • 在解析、记录或将正文排队之前验证签名。
  • 加密验证后将预期存储源和主题列入白名单。
  • 从捕获中编辑地址、联系方式、订单备注和付款元数据。
  • 切勿禁用 TLS 验证或向接收者公开 wp-admin 凭据。

本地架构应与生产相匹配:HTTPS 传输、原始主体身份验证、持久接受、幂等处理、快速响应和可审核的故障。对于具有不同 HMAC 标头的另一个商业提供商,请比较 Shopify 本地 webhook 指南

常见问题

如何在本地主机上测试 WooCommerce Webhooks?
使用 HTTPS 隧道公开您的本地 POST 路由,在 WooCommerce Webhook 设置中输入其公共 URL,在两侧配置相同的密钥,然后触发所选主题。
如何验证 X-WC-Webhook-Signature?
使用配置的 Webhook 密钥在精确的原始请求正文上计算 HMAC-SHA256,对二进制摘要进行 Base64 编码,并将其与标头进行定时安全比较。
为什么 WooCommerce 禁用了我的 webhook?
WooCommerce 在连续五次以上的交付失败后禁用 Webhook。修复连接、超时或响应错误,然后重新激活并再次测试。
在哪里可以查看失败的 WooCommerce Webhook 交付?
打开 WooCommerce → 状态 → 日志并过滤 Webhook 传输日志。将记录的响应与隧道和本地应用程序日志进行比较。