Express使用raw-body限制请求体后express.json()无响应如何解决
问题根因
你编写的代码出现卡顿无响应的核心原因是:自定义中间件中的getRawBody已经将req请求的可读流完全消费读取,而后续调用的express.json()内部默认仍会尝试从req流中读取请求体内容,流被读完后没有新的数据流入,就会一直处于等待状态,最终导致无响应。
另外原有代码还存在一个隐藏bug:如果请求不带content-type头,contentType.parse(cType)会直接抛出错误,导致服务异常。
实现方案
方案一:无需额外依赖(推荐)
如果不需要提前获取原始请求体做其他处理,直接通过Express内置能力即可实现需求,代码更轻量:
const express = require('express') const app = express() // 全局统一校验所有请求的请求体长度,忽略content-type app.use(function(req, res, next) { const MAX_SIZE = 1024 * 1024 // 1mb const contentLength = parseInt(req.headers['content-length'] || '0', 10) if (contentLength > MAX_SIZE) { const err = new Error('Payload Too Large') err.status = 413 return next(err) } next() }) // 仅对content-type为json的请求解析请求体,额外加长度限制做兜底 app.use(express.json({ limit: '1mb' }))
方案二:保留原始请求体读取逻辑
如果业务确实需要提前读取完整的原始请求体做其他处理,可以改造为自行解析JSON,不再调用默认的express.json():
const express = require('express') const contentType = require('content-type') const getRawBody = require('raw-body') const app = express() // 统一读取所有请求的原始请求体,限制1mb长度 app.use(async function(req, res, next) { try { const cType = req.headers['content-type'] || '' let charset = 'utf8' // 兼容无content-type的场景,避免解析报错 if (cType) { charset = contentType.parse(cType).parameters.charset || 'utf8' } const rawBody = await getRawBody(req, { length: req.headers['content-length'], limit: '1mb', encoding: charset }) // 挂载原始请求体到req对象,供后续业务使用 req.rawBody = rawBody next() } catch (err) { next(err) } }) // 仅对json类型请求做解析 app.use(function(req, res, next) { const cType = req.headers['content-type'] || '' if (cType.includes('application/json')) { try { req.body = JSON.parse(req.rawBody.toString()) } catch (parseErr) { parseErr.status = 400 return next(parseErr) } } else { // 非json类型请求,req.body默认设为空对象,和Express默认行为对齐 req.body = {} } next() })
内容的提问来源于stack exchange,提问作者rbehzadan
相关产品推荐
相关产品推荐

