You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在Shopify应用安装时自动创建商品删除Webhook

解决方案

核心思路

在应用OAuth安装回调完成后,利用获取到的店铺Access Token调用Shopify Admin API自动注册products/delete类型的Webhook,同时配置Webhook接收端点处理商品删除事件,同步操作MySQL数据库。


步骤1:配置Shopify应用上下文与OAuth流程

确保你的应用已初始化Shopify API上下文,并包含必要权限(read_products是注册商品删除Webhook的必备权限):

const { Shopify } = require('@shopify/shopify-api');

Shopify.Context.initialize({
  API_KEY: process.env.SHOPIFY_API_KEY,
  API_SECRET_KEY: process.env.SHOPIFY_API_SECRET,
  SCOPES: ['read_products'], // 必须包含该权限
  HOST_NAME: process.env.SHOPIFY_APP_HOST.replace(/https?:\/\//, ''),
  API_VERSION: '2024-04', // 使用Shopify最新稳定API版本
  IS_EMBEDDED_APP: true,
});

步骤2:在OAuth回调中自动注册Webhook

应用安装完成后,OAuth回调会返回店铺会话信息,此时调用Webhook注册API:

async function handleOAuthCallback(req, res) {
  try {
    // 验证OAuth回调并获取会话
    const session = await Shopify.Auth.validateAuthCallback(
      req,
      res,
      req.query
    );

    // 注册商品删除Webhook
    const webhookRegistration = await Shopify.Webhooks.Registry.register({
      shop: session.shop,
      accessToken: session.accessToken,
      topic: 'products/delete', // 指定Webhook类型
      path: '/webhooks/products-delete', // 你的Webhook接收端点
      // 直接定义Webhook处理逻辑
      webhookHandler: async (topic, shop, rawBody) => {
        const productData = JSON.parse(rawBody);
        const shopifyProductId = productData.id;

        // 同步删除MySQL中的对应商品
        const mysql = require('mysql2/promise');
        const dbConnection = await mysql.createConnection({
          host: process.env.MYSQL_HOST,
          user: process.env.MYSQL_USER,
          password: process.env.MYSQL_PASSWORD,
          database: process.env.MYSQL_DB_NAME,
        });

        await dbConnection.execute(
          'DELETE FROM products WHERE shopify_product_id = ?',
          [shopifyProductId]
        );
        await dbConnection.end();
      },
    });

    if (webhookRegistration.success) {
      console.log('商品删除Webhook注册成功');
    } else {
      console.error('Webhook注册失败:', webhookRegistration.result);
    }

    // 跳转到应用后台页面
    res.redirect('/dashboard');
  } catch (error) {
    console.error('OAuth回调处理失败:', error);
    res.status(500).send('安装失败');
  }
}

// 挂载OAuth回调路由(以Express为例)
app.get('/auth/callback', handleOAuthCallback);

步骤3:配置Webhook接收端点与签名验证

Shopify发送Webhook时会附带签名,必须验证签名合法性,防止恶意请求:

app.post('/webhooks/products-delete', async (req, res) => {
  try {
    // 获取Shopify发送的签名与店铺信息
    const hmacHeader = req.headers['x-shopify-hmac-sha256'];
    const shopDomain = req.headers['x-shopify-shop-domain'];
    // 读取原始请求体(必须未解析,否则签名验证会失败)
    const rawBody = await new Promise((resolve) => {
      let data = '';
      req.on('data', chunk => data += chunk);
      req.on('end', () => resolve(data));
    });

    // 验证Webhook签名
    const isValid = Shopify.Webhooks.validate({
      rawBody,
      hmac: hmacHeader,
      shop: shopDomain,
      apiSecretKey: Shopify.Context.API_SECRET_KEY,
    });

    if (!isValid) {
      return res.status(401).send('无效的Webhook签名');
    }

    // 若已在注册时定义handler,这里可直接返回200;否则重复处理逻辑
    res.status(200).send('OK');
  } catch (error) {
    console.error('Webhook处理失败:', error);
    res.status(500).send('处理失败');
  }
});

关键注意事项

  • HTTPS要求:Webhook接收端点必须是公开可访问的HTTPS地址,本地开发可使用ngrok等工具转发
  • 快速响应:处理Webhook时需尽快返回200状态码,Shopify会在超时未响应时重试
  • 权限检查:确保应用的OAuth scopes包含read_products,否则无法注册商品相关Webhook
  • 错误重试:可在MySQL删除逻辑中添加错误日志,便于排查同步失败情况

内容的提问来源于stack exchange,提问作者Hans Handanov

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.09 10:45:34