使用Express JSON中间件接收Shopify Webhook时出现400 Bad Request问题
问题原因
- Express 中间件是按注册顺序执行的,你添加的
express.urlencoded({extended: true})和express.json()属于全局中间件,会在所有路由之前解析请求体。 - HTTP 请求体只能被解析一次,当这两个全局中间件先处理了 Shopify Webhook 的 POST 请求后,后续 Webhook 路由里的
express.text({type: '*/*'})就无法再读取原始未修改的请求体字符串了。 - Shopify Webhook 的签名验证逻辑完全依赖原始请求体生成校验值,一旦
rawBody不是原始内容,验证就会失败,直接返回 400 Bad Request。
解决方案
有两种实用的处理方式,任选其一即可:
方式1:调整路由注册顺序
把 Webhook 路由放在全局解析中间件之前注册,这样全局中间件就不会处理 Webhook 的请求,让路由自身的express.text来解析原始请求体:
// 先注册Webhook路由,确保它先于全局解析中间件执行 app.post('/webhooks', express.text({type: '*/*'}), async (req, res) => { try { const d = await shopify.webhooks.process({ rawBody: req.body, rawRequest: req, rawResponse: res, }); console.log('PROCESS'); } catch (e) { Sentry.captureException(e); } }); // 再注册全局解析中间件,处理其他路由的请求 app.use(express.urlencoded({extended: true})); app.use(express.json());
方式2:限制全局中间件的作用范围
给全局解析中间件添加路径过滤,只让它们处理非 Webhook 路径的请求:
// 仅对/webhooks以外的路径应用解析中间件 app.use(/^(?!\/webhooks).*/, express.urlencoded({extended: true})); app.use(/^(?!\/webhooks).*/, express.json()); // 之后注册Webhook路由 app.post('/webhooks', express.text({type: '*/*'}), async (req, res) => { try { const d = await shopify.webhooks.process({ rawBody: req.body, rawRequest: req, rawResponse: res, }); console.log('PROCESS'); } catch (e) { Sentry.captureException(e); } });
内容的提问来源于stack exchange,提问作者Ömer Ok
相关产品推荐
相关产品推荐

