要在本地测试 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 验证失败
最常见问题,按序检查:
- 密钥是否正确。店铺级 webhook 用 Settings > Notifications 中的「Webhook signing secret」;应用级用应用 API secret。
- 是否对原始请求体哈希,而不是解析后的 JSON 对象。
- 摘要是否为 base64,不是 hex。
- 验证前是否有中间件改动了 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_request、customers/redact、shop/redact)对公开应用为强制要求,在开发店很难自然触发。建议捕获一份真实负载保存后,用 HookNexus 重放 在改代码时反复投递。Shopify 集成文档 中有更完整说明。
下一步
本地 Shopify webhook 流程跑通后,可继续:
- 阅读 Shopify 集成指南,了解批量操作 webhook、编程管理订阅等进阶主题。
- 在开发环境中长期配置 webhook 转发,让 Shopify 事件自动到达本机。
- 使用 webhook 重放 复测边界场景,无需重复操作店铺——对结账、退款与合规事件特别有用。
- 阅读 完整 Shopify 集成文档,了解生产部署、签名中间件与事件去重等模式。
- 用 webhook 调试器 同时对接 Stripe、Slack 等其他平台。