Nest-管道

概念

Nest 中的 管道(Pipe) 是一个带 @Injectable() 且实现了 PipeTransform 接口的类。管道在「控制器方法被调用前」执行,所以非常适合做入参的校验与预处理。

职责

  1. 验证 ------ 数据不符合规则就直接抛异常,请求进不到控制器;
  2. 转换 ------ 把入参改成我们想要的形式(字符串→数字、普通对象→DTO 实例等)。

内置管道(开箱即用)

Nest 自带 10 个左右的常用管道,下面 3 个最常见:

管道 作用 用法示例
ParseIntPipe 把字符串参数转成整数,失败抛 400 @Param('id', ParseIntPipe) id: number
ValidationPipe 结合 class-validator,自动按 DTO 装饰器校验整个 Body @Body() dto: CreateUserDto + 全局 app.useGlobalPipes(new ValidationPipe())
DefaultValuePipe 没传参时塞一个默认值 @Query('page', new DefaultValuePipe(1)) page: number

自定义管道

  1. 实现 PipeTransform 接口,写 transform(value, metadata) 方法;
  2. 返回「转换后的值」或「原值」;
  3. 校验失败直接抛 BadRequestException 即可。

小栗子

生成管道

bash 复制代码
nest g pipe common/pipes/hex-to-int

逻辑实现

ts 复制代码
// src/common/pipes/hex-to-int.pipe.ts
import { PipeTransform, Injectable, ArgumentMetadata, BadRequestException } from '@nestjs/common';

@Injectable()
export class HexToIntPipe implements PipeTransform<string, number> {
  transform(value: string, meta: ArgumentMetadata): number {
    const intVal = parseInt(value, 16);   // 按 16 进制解析
    if (isNaN(intVal)) {
      throw new BadRequestException(`"${value}" 不是合法 16 进制字符串`);
    }
    return intVal;   // 返回转换后的 10 进制数字
  }
}

控制器使用

ts 复制代码
@Get('color/:hex')
getColor(@Param('hex', HexToIntPipe) color: number) {
  // color 已经是数字,例如 0xff → 255
  return { color, binary: color.toString(2) };
}

类验证器

Nest 与 class-validator 库能很好地协同工作。这个强大的库允许你使用基于装饰器的验证。基于装饰器的验证功能极其强大,特别是与 Nest 的管道功能结合使用时,因为我们可以访问被处理属性的 metatype。

使用

bash 复制代码
npm i --save class-validator class-transformer

1. class-validator ------ 「校验」专家
作用:在运行期根据装饰器规则,验证一个对象里的字段是否合法;不合法就抛详细的错误信息。

核心装饰器(常用 10 个)

装饰器 含义
@IsString() 必须是字符串
@IsInt() / @IsNumber() 必须是整数 / 数字
@IsEmail() 合法邮箱格式
@IsOptional() 允许缺失或 undefined
@IsNotEmpty() 不能是空字符串、null、undefined
@Min(0) / @Max(100) 数值上下界
@Length(2, 20) 字符串长度
@IsEnum(Role) 值必须在枚举里
@IsArray() / @ArrayMinSize(1) 数组及其长度
@ValidateNested() + @Type(()=>ChildDto) 嵌套对象/数组校验
小栗子

创建DTO并贴装饰器

ts 复制代码
import { IsNotEmpty, IsString, Length } from 'class-validator';
export class SigninUserDto {
    @IsString()
    @IsNotEmpty()
    @Length(3, 10, {
        // $value: 用户传入的值
        // $property: 属性名
        // $target: 当前类
        // $constraint1: 3  最小长度
        // $constraint2: 10 最大长度
        message: '用户名长度必须在3到10个字符之间,当前传递的值为: $value',
    })
    username: string;
    
    @IsString()
    @IsNotEmpty()
    @Length(6, 10, {
        message: '密码长度必须在6到10个字符之间,当前传递的值为: $value',
    })
    password: string;
}

控制器中接入DTO

ts 复制代码
@Post('signin')
    signin(@Body() loginDto: SigninUserDto) {   
        const {username, password } = loginDto
        return this.authService.signin(username, password);
}
    

全局开启ValidationPipe(main.ts)

ts 复制代码
// 全局拦截器
app.useGlobalPipes(new ValidationPipe({
  // 去除实体中不存在的字段
  // whitelist: true,
  //  额外报错,防止客户端乱传。
	//forbidNonWhitelisted: true
}))

2. class-transformer ------ 「转换」专家

作用:把普通对象(例如 JSON 解析后都是字面量)转换成类实例,并可在转换时做字段改名、类型强制、嵌套实例化等操作;同时提供反向能力(把实例变回普通对象)。

核心API

API 作用
plainToInstance(Target, plain) 把纯对象 → 类实例
instanceToPlain(instance) 把类实例 → 纯对象
plainToClassFromExist(existing, plain) 在已有实例上合并数据
expose / exclude 系列装饰器 控制序列化/反序列化时哪些字段可见

常用装饰器

装饰器 含义
@Type(()=>Type) 指定字段要实例化的目标类(解决嵌套)
@Transform(({value})=>fn(value)) 自定义转换函数
@Expose() / @Exclude() 显式暴露或排除字段
@Expose({name:'_id'}) 把后端字段 _id 映射到前端 id
小栗子

定义实体类

ts 复制代码
// user.entity.ts
import { Expose, Type, Transform } from 'class-transformer';

export class User {
  @Expose({ name: '_id' })        // 数据库字段叫 _id,序列化后叫 id
  id: string;

  email: string;

  @Exclude()                      // 返回前端时永远去掉密码
  password: string;

  @Type(() => Date)               // 把时间戳/字符串 → Date 实例
  createdAt: Date;

  @Transform(({ value }) => value ?? 'USER')  // 缺省值
  role: string;
}

手动转换(在 service 里)

ts 复制代码
const user = plainToInstance(User, userRecord); // userRecord 是 Mongo 原始对象
return instanceToPlain(user);                   // 返回给控制器 → 自动去掉 password 等

配合 ValidationPipe 嵌套校验

ts 复制代码
export class CreateOrderDto {
  @ValidateNested()
  @Type(() => OrderItemDto)   // 必须同时加,否则 class-validator 拿不到实例
  items: OrderItemDto[];
}

前端 JSON 数据校验与转换流程

流程说明:

  1. 前端发送 JSON 数据到后端。
  2. 后端使用 ValidationPipe 处理数据。
  3. ValidationPipe 内部先调用 class-transformer 将普通对象转换为 DTO 实例。
  4. 然后使用 class-validator 对 DTO 实例进行校验。
  5. 控制器接收到已转换且校验通过的数据。
  6. 业务逻辑处理完成后,使用 class-transformer 将实体转换回普通对象。
  7. 最终将普通对象返回给前端。
相关推荐
砖厂小工42 分钟前
用 GLM + OpenClaw 打造你的 AI PR Review Agent — 让龙虾帮你审代码
android·github
全栈老石1 小时前
拆解低代码引擎核心:元数据驱动的"万能表"架构
数据库·低代码
张拭心1 小时前
春节后,有些公司明确要求 AI 经验了
android·前端·人工智能
张拭心2 小时前
Android 17 来了!新特性介绍与适配建议
android·前端
SimonKing3 小时前
OpenCode AI辅助编程,不一样的编程思路,不写一行代码
java·后端·程序员
FastBean3 小时前
Jackson View Extension Spring Boot Starter
java·后端
Kapaseker4 小时前
Compose 进阶—巧用 GraphicsLayer
android·kotlin
黄林晴4 小时前
Android17 为什么重写 MessageQueue
android
Seven974 小时前
剑指offer-79、最⻓不含重复字符的⼦字符串
java
皮皮林55114 小时前
Java性能调优黑科技!1行代码实现毫秒级耗时追踪,效率飙升300%!
java