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. 最终将普通对象返回给前端。
相关推荐
福大大架构师每日一题17 小时前
Redis 8.10.0 正式发布:紧凑哈希、批量导入、备份恢复、流与时序能力全面升级
数据库·redis·哈希算法
周GZ17 小时前
简单讲解Java中静态方法与 实例方法
java·开发语言
疯狂打码的少年17 小时前
【数据结构】树的基本概念与二叉树定义
java·数据结构·笔记·算法
一笑的小酒馆17 小时前
Android视频直播播放器简单封装
android
雨晨源码(同名B站)17 小时前
基于深度学习YoloV11农业病害虫害检测系统 智慧农业信息化综合管理平台 (附源码+lw文档+ppt)
数据库·人工智能·深度学习·yolo·信息可视化
盗理者18 小时前
AI Agent 技能分享|SQL 性能诊断与优化
java·sql·spring·skill
GitLqr18 小时前
Java 26 终于原生支持 HTTP/3 了:告别 Netty,直接用 QUIC
java·netty·http3
用户409666013175118 小时前
Jackson 序列化:@JsonIgnore / @JsonProperty / @JsonFormat / @JsonInclude / @JsonUnwrapped 一次讲清楚
java·后端
码路漫漫18 小时前
用了 Caffeine,消息为什么还是被处理了两次?
java
DBA小马哥18 小时前
向量数据库入门到进阶:Embedding、ANN算法与RAG落地的关键术语
数据库·算法·embedding