如何禁用NestInterceptor自动序列化?自定义响应拦截器数据序列化问题
问题:NestInterceptor包装响应后data被序列化为字符串的解决方法
我用以下NestInterceptor给最终响应统一添加code、message和data字段:
export class HttpResponseInterceptor implements NestInterceptor { intercept(context: ExecutionContext, next: CallHandler): Observable<any> { return next.handle().pipe(map(data => ({ code: 200, message: 'ok', data: data })) ); } }
期望得到的响应格式:
{ "code": 200, "message": "ok", "data": { "vip": 333, "enterprise": 14, "pension": 712 } }
但实际得到的结果里,data变成了JSON字符串:
{ "code": 200, "message": "ok", "data": "{\"vip\":333,\"enterprise\":14,\"pension\":712}" }
补充说明:移除GlobalFilters无效,当前仅启用了这个GlobalInterceptors。
解决方法
1. 检查控制器的返回逻辑
这是最常见的原因:你的控制器可能已经手动把响应数据序列化为字符串了(比如用了JSON.stringify(),或者直接调用res.send(JSON.stringify(...))),导致Interceptor拿到的是字符串而非原始对象。
修正方式:控制器直接返回JavaScript对象,不要手动序列化。比如:
// 正确写法 @Get('/data') getData() { return { vip: 333, enterprise: 14, pension: 712 }; } // 错误写法(会导致Interceptor拿到字符串) @Get('/data') getData(@Res() res) { res.send(JSON.stringify({ vip: 333, ... })); }
2. 在Interceptor中手动解析字符串(应急方案)
如果无法修改控制器的返回逻辑(比如依赖第三方代码),可以在Interceptor里判断data类型,尝试将字符串解析为对象:
export class HttpResponseInterceptor implements NestInterceptor { intercept(context: ExecutionContext, next: CallHandler): Observable<any> { return next.handle().pipe(map(data => { let parsedData = data; // 仅当data是字符串时尝试解析 if (typeof data === 'string') { try { parsedData = JSON.parse(data); } catch (err) { // 解析失败则保留原数据,避免报错 } } return { code: 200, message: 'ok', data: parsedData }; })); } }
3. 避免直接操作响应对象
如果控制器中使用了@Res()装饰器直接操作响应对象,会绕过Nest的默认序列化机制,导致返回字符串。这种情况下应该尽量使用Nest的标准返回方式,或者在使用@Res()时加上{ passthrough: true }参数,让Nest继续处理响应:
@Get('/data') getData(@Res({ passthrough: true }) res) { // 可以操作res的其他属性,但返回对象交给Nest处理 res.setHeader('X-Custom-Header', 'value'); return { vip: 333, ... }; }
内容的提问来源于stack exchange,提问作者Hhry
相关产品推荐
相关产品推荐

