Node.js/Express中捕获并使用格式错误的JSON POST请求及路由级错误中间件不生效问题
Node.js/Express中捕获并使用格式错误的JSON POST请求及路由级错误中间件不生效问题
我来帮你拆解并解决这两个问题:
一、处理格式不标准的JSON请求
你遇到的核心问题是:请求头标了application/json,但body是不符合严格JSON规范的(比如键没有双引号的{ something: "data" }),而Express默认的express.json()中间件只支持严格JSON解析,所以会抛出语法错误。
这里有两种靠谱的解决思路:
1. 使用宽松JSON解析库(推荐)
可以用json5这个库,它支持无引号键、单引号字符串等宽松格式的JSON解析。步骤如下:
- 先安装依赖:
npm install json5 - 替换默认的JSON解析中间件,用自定义逻辑读取原始body并解析:
const express = require('express'); const JSON5 = require('json5'); const router = express.Router(); // 自定义中间件:处理宽松格式的JSON router.use((req, res, next) => { // 只处理Content-Type为application/json的请求 if (req.headers['content-type']?.includes('application/json')) { let rawBody = ''; // 读取原始请求body req.on('data', chunk => rawBody += chunk); req.on('end', () => { try { // 用JSON5解析宽松格式 req.body = JSON5.parse(rawBody); next(); } catch (err) { // 解析失败时,把错误传给错误处理中间件 next(err); } }); } else { // 非JSON请求直接跳过 next(); } }); // 你的POST路由 router.post('/post', (req, res) => { console.log('解析后的请求体:', req.body); res.send('POST 请求已接收'); });
2. 捕获默认解析错误后重新尝试解析
如果不想引入第三方库,也可以先保留express.json(),但需要先读取原始body,解析失败后再用宽松方式重试:
const express = require('express'); const JSON5 = require('json5'); const router = express.Router(); // 先把JSON请求读取为原始buffer router.use(express.raw({ type: 'application/json' })); // 尝试用宽松格式解析 router.use((req, res, next) => { try { req.body = JSON5.parse(req.body.toString()); next(); } catch (err) { next(err); } });
二、路由级错误中间件不生效的原因及修复
你的路由级错误中间件没触发,主要有两个关键原因:
1. 错误中间件的挂载顺序错误
Express的中间件是按挂载顺序依次执行的,错误处理中间件(带4个参数的(err, req, res, next))必须放在所有业务路由和普通中间件之后,这样前面抛出的错误才能被它捕获。你之前把错误中间件放在了路由最前面,自然抓不到后面路由抛出的错误。
2. 解析错误发生在路由栈之外
如果你的express.json()是挂载在app级(比如app.use(express.json())),那么JSON解析错误会在请求进入路由栈之前就发生,这时候路由级的错误中间件根本没机会处理,只能用app级的错误中间件捕获。
修复后的路由代码示例
把解析中间件、业务路由、错误处理中间件按正确顺序挂载,并且把解析逻辑放在路由内部,确保错误发生在路由栈内:
const express = require('express'); const JSON5 = require('json5'); const router = express.Router(); // 1. 先挂载解析中间件 router.use(express.raw({ type: 'application/json' })); router.use((req, res, next) => { try { req.body = JSON5.parse(req.body.toString()); next(); } catch (err) { next(err); // 把错误传给后续的错误处理中间件 } }); // 2. 挂载业务路由 router.post('/post', (req, res) => { console.log(req.body); res.send('POST'); }); // 3. 最后挂载路由级错误处理中间件 router.use((error, req, res, next) => { console.log("Error handling middleware called..."); if(error instanceof SyntaxError) { switch(error.type) { case 'entity.parse.failed': console.log('JSON格式不正确'); break; default: console.log('其他语法错误'); break; } res.status(400).send('请求JSON格式错误'); } else { next(error); // 非解析错误,继续传给上层错误中间件 } }); module.exports = router;
这样调整后,路由级的错误中间件就能正常捕获解析过程中的错误了。
备注:内容来源于stack exchange,提问作者Morgan
相关产品推荐
相关产品推荐

