Shopify 指南

如何在本地测试 Shopify Webhook

用 HookNexus 测试订单、商品、应用生命周期与合规类 Shopify webhook:捕获真实负载、检查请求头,并转发到本地 Shopify 应用。

要在本地测试 Shopify webhook,需要让 Shopify 指向一个能接收事件的公网端点,再把请求转发到本机开发服务器。这样可以在不把本机直接暴露到公网的情况下,接收真实的订单、商品与库存负载。典型流程是:用 HookNexus 等工具创建公网 URL,在 Shopify 中注册,触发店铺操作,检查捕获的请求,再转发到本地应用做处理与 HMAC 验证。

为什么 Shopify webhook 本地测试麻烦

Shopify 要求每个 webhook 目标必须是可公网访问的 HTTPS URL。不能把 http://localhost:3000/webhooks 填进后台就指望能通——这是多数开发者遇到的第一个门槛。

除 URL 外,Shopify 会用应用共享密钥对负载做 HMAC-SHA256 签名。处理器必须针对原始请求体验证签名。若框架在你能读到原始字节之前就解析了 body,验证会默默失败,你会花大量时间调试一个其实不是逻辑 bug 的问题。

开发店与生产环境的差异

开发店与正式店行为略有不同:部分 webhook 主题触发更少、限流更宽松,而像 orders/paid 这类事件依赖支付网关在测试模式。仍推荐在开发店测试,但了解这些差异能省时间。

投递时序与重试

Shopify 对失败投递最多在 48 小时内重试 19 次。本地开发时若事件触发时处理器宕机,恢复后可能收到一波重试。采用「先捕获再转发」时,公网端点始终对 Shopify 返回 200,可避免这一问题。

开始前的准备

动手前请确认已具备:

  • Shopify 店铺 —— Partner 后台里的开发店即可,无需正式店。
  • Webhook 注册方式 —— 店铺级:Shopify 后台 Settings > Notifications;应用级:Partner 后台或 Shopify API。
  • 公网端点 URL —— Shopify 投递的目标。HookNexus 可即时生成。
  • 应用共享密钥 —— 在 Shopify 后台应用设置中查看,HMAC 验证必需。
  • 本地开发服务器 —— Express、Next.js 等在本机 localhost 上运行。

分步本地测试流程

第一步 —— 创建公网 webhook 端点

登录 HookNexus 并新建端点。你会得到形如 https://api.hooknexus.com/h/abc123 的唯一公网 URL。该 URL 立即可用,任何发往它的 POST 都会被记录完整请求头与 body,供查看。

第二步 —— 在 Shopify 注册端点

根据场景二选一:

店铺级 webhook(通知): 进入 Shopify 后台 Settings > Notifications,滚动到底部 Webhooks,点击「Create webhook」。选择事件主题(如 orders/create),格式选 JSON,粘贴 HookNexus 端点 URL。

应用级 webhook: 若在开发 Shopify 应用,通过 Partner 后台或 Admin API 注册:

curl -X POST "https://your-store.myshopify.com/admin/api/2024-01/webhooks.json" \
  -H "X-Shopify-Access-Token: YOUR_ACCESS_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "webhook": {
      "topic": "orders/create",
      "address": "https://api.hooknexus.com/h/abc123",
      "format": "json"
    }
  }'

第三步 —— 触发测试事件

注册完成后,执行对应店铺操作。orders/create:在开发店用 Bogus 支付网关下测试单。products/update:修改任意商品的标题或价格。通常几秒内会触发 webhook。

若注册的是 carts/update,在店面购物车加商品。app/uninstalled:在开发环境卸载并重装应用(勿在正式环境随意操作)。

第四步 —— 检查捕获的请求

打开 HookNexus 控制台,选择你的端点,查看入站请求详情:

  • Headers —— 关注 X-Shopify-Hmac-Sha256(HMAC 签名)、X-Shopify-Topic(如 orders/create)、X-Shopify-Shop-Domain(发送店铺)。
  • Body —— 完整 JSON,含订单明细、行项、客户信息等。
  • Timing —— 到达时间与投递耗时。

在涉及本地代码之前,先确认 Shopify 发送的内容符合预期。

第五步 —— 转发到 localhost

使用 HookNexus CLI 将捕获的 webhook 转到本地服务

hooknexus listen abc123 --forward http://localhost:3000/webhooks/shopify

此后到达该端点的每个新 webhook 会实时转发到本地处理器。历史请求也可在控制台 按需重放,迭代代码时无需反复操作店铺。

第六步 —— 在应用中处理并验证

下面是一个完整的 Express 示例:接收转发的 webhook 并验证 Shopify HMAC:

const express = require("express");
const crypto = require("crypto");

const app = express();
const SHOPIFY_SECRET = process.env.SHOPIFY_WEBHOOK_SECRET;

app.post(
  "/webhooks/shopify",
  express.raw({ type: "application/json" }),
  (req, res) => {
    const hmacHeader = req.get("X-Shopify-Hmac-Sha256");
    const topic = req.get("X-Shopify-Topic");

    const generatedHash = crypto
      .createHmac("sha256", SHOPIFY_SECRET)
      .update(req.body)
      .digest("base64");

    if (generatedHash !== hmacHeader) {
      console.error("HMAC verification failed for topic:", topic);
      return res.status(401).send("Unauthorized");
    }

    const payload = JSON.parse(req.body.toString());
    console.log(`Verified ${topic} webhook from ${req.get("X-Shopify-Shop-Domain")}`);
    console.log("Order ID:", payload.id);

    // Process the webhook event
    res.status(200).send("OK");
  }
);

app.listen(3000, () => console.log("Listening on port 3000"));

关键是 express.raw({ type: "application/json" }),确保拿到用于 HMAC 的原始 Buffer,而不是已解析的对象。

Shopify HMAC 验证说明

Shopify 对每个 webhook 请求签名,以便应用确认负载来自 Shopify 且未被篡改。签名在 X-Shopify-Hmac-Sha256 头中,为 base64 编码的 HMAC-SHA256。

任意 Node.js 项目可用的独立验证函数:

const crypto = require("crypto");

function verifyShopifyWebhook(rawBody, hmacHeader, secret) {
  const generatedHash = crypto
    .createHmac("sha256", secret)
    .update(rawBody, "utf8")
    .digest("base64");

  return crypto.timingSafeEqual(
    Buffer.from(generatedHash, "utf8"),
    Buffer.from(hmacHeader, "utf8")
  );
}

// Usage in a request handler:
// const isValid = verifyShopifyWebhook(rawBody, req.get('X-Shopify-Hmac-Sha256'), SECRET);

常见坑

必须原始 body: HMAC 必须基于 Shopify 发送的确切字节。若框架默认用 express.json() 自动解析 JSON,再序列化可能与原始不一致。务必在解析前捕获原始 body。

Base64 编码: Shopify 使用 base64,不是 hex。误用 .digest("hex") 会导致验证永远失败。

恒定时间比较:crypto.timingSafeEqual() 代替 ===,降低时序攻击风险。两 Buffer 须等长,需处理请求头缺失或格式错误的情况。

Shopify 测试中的常见问题

HMAC 验证失败

最常见问题,按序检查:

  1. 密钥是否正确。店铺级 webhook 用 Settings > Notifications 中的「Webhook signing secret」;应用级用应用 API secret。
  2. 是否对原始请求体哈希,而不是解析后的 JSON 对象。
  3. 摘要是否为 base64,不是 hex。
  4. 验证前是否有中间件改动了 body。

收不到事件

已注册但控制台无事件时:

  • 确认 Shopify 后台中注册为激活状态(绿色指示)。
  • 确认端点 URL 正确且公网可达。
  • 查看 Shopify webhook 投递日志(Admin > Settings > Notifications > Webhooks)中的失败与错误码。
  • 确认触发了正确操作:orders/create 仅在新订单创建时触发,更新旧订单不会触发。

开发店限制

开发店需注意:

  • orders/paid 等支付类 webhook 需在测试模式下配置 Bogus 支付网关。
  • 部分与 Shopify Payments 或发货标签相关的主题在开发店不可用。
  • 开发店投递延迟可能略高于生产。

若某主题在开发店受限,可保存一份真实捕获的负载,通过 HookNexus 重放 继续测处理器逻辑。

快速检查清单

对照本清单确认 Shopify webhook 测试环境就绪:

  • 已创建并可从 Shopify Admin 访问开发店
  • 已创建 HookNexus 端点并复制 URL
  • 已在 Shopify 注册 webhook,主题与 URL 正确
  • Shopify webhook 签名密钥已写入环境变量
  • 已触发测试操作且在 HookNexus 控制台看到捕获
  • Express(或等价)路由使用 raw body 中间件,而非默认 JSON 解析
  • HMAC 使用 base64 摘要并完成恒定时间比较
  • 已用 hooknexus listen 将流量指向 localhost 测试转发

常见问题

没有正式店能测 Shopify webhook 吗?

可以。Partner 后台的免费开发店支持大多数 webhook 主题,可像生产环境一样创建订单、更新商品、触发应用生命周期事件。结账相关事件由 Bogus 支付网关覆盖。少数仅限正式店的主题,可对已捕获负载使用 重放 测处理器。

代码看起来对,为什么 HMAC 还是失败?

最常见原因是 Web 框架在读取原始字节前就解析了 JSON。Shopify 的 HMAC 基于原始 body;Express 等用 express.json() 自动解析后,再序列化可能不同(空白、键顺序等)。在 webhook 路由使用 express.raw({ type: "application/json" }) 接收原始 Buffer。

必须返回特定状态码给 Shopify 吗?

任意 2xx 即表示投递成功。若返回 4xx/5xx 或超过 5 秒超时,Shopify 会记为失败并在 48 小时内最多重试 19 次。把 HookNexus 作为捕获端点时,它会立即返回 200,Shopify 不会重试——你可按需转发或重放到本地任意多次。

如何测试客户数据请求等合规 webhook?

合规类 webhook(customers/data_requestcustomers/redactshop/redact)对公开应用为强制要求,在开发店很难自然触发。建议捕获一份真实负载保存后,用 HookNexus 重放 在改代码时反复投递。Shopify 集成文档 中有更完整说明。

下一步

本地 Shopify webhook 流程跑通后,可继续:

  • 阅读 Shopify 集成指南,了解批量操作 webhook、编程管理订阅等进阶主题。
  • 在开发环境中长期配置 webhook 转发,让 Shopify 事件自动到达本机。
  • 使用 webhook 重放 复测边界场景,无需重复操作店铺——对结账、退款与合规事件特别有用。
  • 阅读 完整 Shopify 集成文档,了解生产部署、签名中间件与事件去重等模式。
  • webhook 调试器 同时对接 Stripe、Slack 等其他平台。