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

WooCommerce Webhook签名验证失败:Node.js后端集成问题排查

解决WooCommerce Webhook签名验证不匹配的问题

我来帮你搞定这个签名验证失败的问题——核心原因其实出在你对请求体的处理方式上!

问题根源

你用了bodyParser.json()中间件,它会把HTTP请求的原始JSON字符串解析成JavaScript对象。但WooCommerce生成Webhook签名时,是基于原始的请求体字符串(也就是未被解析的、直接从HTTP请求里拿到的纯文本)来计算HMAC-SHA256哈希的。

当你用req.body(解析后的对象)传给CryptoJS时,CryptoJS会把这个对象重新序列化成字符串,但这个序列化后的格式和WooCommerce发送的原始字符串大概率不一样(比如键的顺序、空格、引号的处理细节),最终导致生成的哈希和签名不匹配。

修复方案

我们需要先获取原始的请求体字符串,用它来计算哈希,验证通过后再把原始字符串解析成JSON对象处理业务逻辑。具体步骤如下:

1. 安装依赖(如果用raw-body的话)

首先安装raw-body模块,它能帮我们方便地获取原始请求体:

npm install raw-body

2. 修改路由代码

替换掉原来的body-parser相关代码,改用原始请求体来计算哈希:

const rawBody = require('raw-body');
const CryptoJS = require('crypto-js');

router.post('/', async function (req, res) {
  try {
    const secret = 'ciPV6gjCbu&efdgbhfgj&¤"#&¤GDA';
    const signature = req.header("x-wc-webhook-signature");
    
    // 获取原始的请求体字符串
    const rawRequest = await rawBody(req, {
      encoding: 'utf8'
    });
    
    // 基于原始字符串计算HMAC-SHA256并转Base64
    const hash = CryptoJS.HmacSHA256(rawRequest, secret).toString(CryptoJS.enc.Base64);
    
    if(hash === signature){
      // 验证通过后,再解析原始字符串为JSON对象处理业务
      const requestBody = JSON.parse(rawRequest);
      console.log('Webhook验证成功,请求内容:', requestBody);
      res.send('match');
    } else {
      console.log('哈希不匹配', { 计算出的哈希: hash, 收到的签名: signature });
      res.send("no match");
    }
  } catch (err) {
    console.error('处理Webhook请求出错:', err);
    res.status(400).send('Bad Request');
  }
});

可选:用Node.js内置的crypto模块(更高效)

如果你不想用CryptoJS,也可以用Node.js自带的crypto模块来计算哈希,代码如下:

const crypto = require('crypto');
const rawBody = require('raw-body');

router.post('/', async function (req, res) {
  try {
    const secret = 'ciPV6gjCbu&efdgbhfgj&¤"#&¤GDA';
    const signature = req.header("x-wc-webhook-signature");
    
    const rawRequest = await rawBody(req, { encoding: 'utf8' });
    
    // 用内置crypto生成HMAC
    const hmac = crypto.createHmac('sha256', secret);
    hmac.update(rawRequest);
    const hash = hmac.digest('base64');
    
    if(hash === signature){
      const requestBody = JSON.parse(rawRequest);
      res.send('match');
    } else {
      res.send("no match");
    }
  } catch (err) {
    res.status(400).send('Bad Request');
  }
});

额外注意事项

  • 确保你Node.js代码里的secret和WooCommerce后台配置的完全一致,包括所有特殊字符(比如你Secret里的¤,别复制错了)
  • 不要在这个路由之前使用任何会消耗请求体的中间件(比如body-parser.json()),否则raw-body就拿不到原始数据了
  • 检查WooCommerce Webhook的Content-Type设置,默认是application/json,确保和你的请求体编码匹配

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.15 07:34:25