如何在NestJS的Request对象中添加函数返回类型以实现全局序列化
在NestJS中实现全局响应格式序列化(基于返回类型)
1. 自定义@ReturnType装饰器
通过该装饰器标记控制器方法的返回DTO类型,并将类型存储到请求元数据中,供后续拦截器读取。
import { SetMetadata } from '@nestjs/common'; // 定义元数据唯一标识键 export const RETURN_TYPE_KEY = 'returnType'; // 自定义装饰器:接收DTO类作为参数,存入元数据 export const ReturnType = (dto: any) => SetMetadata(RETURN_TYPE_KEY, dto);
2. 实现全局序列化拦截器
创建拦截器,利用Reflector读取元数据中的返回类型,通过class-transformer对响应数据做序列化处理,同时兼容异步返回值、数组等场景。
import { Injectable, NestInterceptor, ExecutionContext, CallHandler } from '@nestjs/common'; import { Reflector } from '@nestjs/core'; import { Observable } from 'rxjs'; import { map } from 'rxjs/operators'; import { plainToInstance } from 'class-transformer'; import { RETURN_TYPE_KEY } from './return-type.decorator'; @Injectable() export class SerializeInterceptor implements NestInterceptor { constructor(private readonly reflector: Reflector) {} intercept(context: ExecutionContext, next: CallHandler): Observable<any> { // 获取当前控制器方法标记的返回DTO类型 const returnType = this.reflector.get(RETURN_TYPE_KEY, context.getHandler()); if (!returnType) { // 未标记返回类型时,直接返回原响应 return next.handle(); } return next.handle().pipe( map(async (data) => { // 解析异步返回的Promise数据 const resolvedData = await Promise.resolve(data); // 处理数组类型:逐个序列化数组元素 if (Array.isArray(resolvedData)) { return resolvedData.map(item => plainToInstance(returnType, item)); } // 处理单个对象:直接序列化 return plainToInstance(returnType, resolvedData); }), ); } }
3. 全局注册拦截器
让拦截器作用于所有模块,有两种常用方式:
方式一:通过AppModule的提供者注册
import { Module } from '@nestjs/common'; import { APP_INTERCEPTOR } from '@nestjs/core'; import { SerializeInterceptor } from './serialize.interceptor'; import { CatsController } from './cats.controller'; import { CatsService } from './cats.service'; @Module({ controllers: [CatsController], providers: [ CatsService, { provide: APP_INTERCEPTOR, useClass: SerializeInterceptor, }, ], }) export class AppModule {}
方式二:在main.ts中直接全局注册
import { NestFactory } from '@nestjs/core'; import { AppModule } from './app.module'; import { SerializeInterceptor } from './serialize.interceptor'; import { Reflector } from '@nestjs/core'; async function bootstrap() { const app = await NestFactory.create(AppModule); app.useGlobalInterceptors(new SerializeInterceptor(new Reflector())); await app.listen(3000); } bootstrap();
4. 在控制器中使用@ReturnType装饰器
结合你提供的示例代码,调整后如下:
import { Controller, Post, Param, Body, ParseIntPipe } from '@nestjs/common'; import { ReturnType } from './return-type.decorator'; import { CatsService } from './cats.service'; import { CreateDto } from './create.dto'; @Controller(':breedId/cats') export class CatsController { constructor(private readonly catsService: CatsService) {} @Post() @ReturnType(CreateDto) create( @Param('breedId', ParseIntPipe) breedId: number, @Body() dto: CreateDto, ): Promise<CreateDto> { return this.catsService.create(breedId, dto); } @Post('list') @ReturnType(CreateDto) async findAll( @Param('breedId', ParseIntPipe) breedId: number, @Body() createDto: CreateDto, ): Promise<CreateDto[]> { return this.catsService.findAll(breedId, createDto); } }
关键说明
class-transformer的plainToInstance方法会严格遵循DTO类上的装饰器(如@Expose、@Exclude)处理数据,确保响应格式符合定义。- 拦截器兼容了异步返回值、数组、单个对象等常见响应场景,无需额外适配。
- 全局注册后,所有标记了
@ReturnType的控制器方法都会自动应用序列化逻辑。
内容的提问来源于stack exchange,提问作者jaswant patel
相关产品推荐
相关产品推荐

