NestJS处理application/json请求时request的data、end事件未触发问题
问题根因
NestJS 默认内置了 body-parser 中间件,会自动预处理 content-type 为 application/json、application/x-www-form-urlencoded 等常见类型的请求:
- 中间件会提前读取完整的请求流,解析成JS对象挂载到
request.body属性上 - 流被消费完毕后就不会再触发
data和end事件,所以你手动监听这两个事件没有响应 text/plain类型不在body-parser默认处理范围内,请求流没有被提前消费,所以你的监听逻辑可以正常执行
解决方案
方案1(最推荐):直接使用NestJS解析好的请求体
无需自己监听流读取请求体,直接用框架提供的 @Body() 装饰器获取解析结果即可,改造后代码如下:
控制器代码:
@Public() @Post(SERVER_COVID_A_CASA_CARE_PLAN_NOTIFICATION_PATH) getNotification(@Body() body: any, @Res() response: Response) { // 直接把解析好的body传给facade,也可以根据需要转成JSON字符串 this.facade.manageCarePlanNotification(JSON.stringify(body), response); }
facade 代码简化为:
manageCarePlanNotification(bodyStr: string, response: Response) { this.manageCarePlanNotificationRequest(bodyStr, response); }
方案2:关闭指定路由的bodyParser预处理
如果你确实需要自行处理原始请求流,可以针对当前路由关闭 body-parser 的自动处理:
- 全局关闭默认bodyParser:
// main.ts const app = await NestFactory.create(AppModule, { bodyParser: false });
- 按需为其他需要自动解析的路由挂载bodyParser中间件,或者只针对当前路由使用raw中间件处理原始流。
方案3:兼容现有逻辑无需大改
直接判断请求类型,application/json 类型直接从 request.body 取解析好的对象转字符串即可:
manageCarePlanNotification(request: Request, response: Response) { // 新增判断:如果body已经被解析过,直接用 if (request.headers['content-type'] === 'application/json' && request.body) { this.manageCarePlanNotificationRequest(JSON.stringify(request.body), response); return; } // 原有处理text/plain的逻辑保留 let jsonBodyReq = ''; request.on('data', function (data) { jsonBodyReq += data; }); request.on('end', () => { this.manageCarePlanNotificationRequest(jsonBodyReq, response); }); request.on('error', function (e) { console.log(e.message); }); }
内容的提问来源于stack exchange,提问作者Cri。
相关产品推荐
相关产品推荐

