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. 最终将普通对象返回给前端。
相关推荐
剽悍一小兔2 小时前
为什么使用postman发送请求时不会有跨域问题?
java
Cherry的跨界思维2 小时前
19、自动化处理双核心:Java规则引擎与Python Selenium实战全解析
java·开发语言·python·自动化·办公自动化·python办公自动化·python办公
熊小猿2 小时前
学生管理系统(前后端+数据库)完整思路总结
数据库
綝~2 小时前
MySQL的相关内容
数据库·mysql
思成不止于此2 小时前
【MySQL 零基础入门】DQL 核心语法(一):学生表基础查询与聚合函数篇
数据库·笔记·学习·mysql
nbsaas-boot2 小时前
MySQL 中如何实现类似 SQL Server SELECT INTO 的表复制能力(生产级实践指南)
数据库·mysql
hunter1990102 小时前
Spring线程池ThreadPoolTaskExecutor配置与实践
java·后端·spring
皇族崛起2 小时前
【docker安装部署】- 一个可用的Docker 镜像配置 和 DNS配置
java·docker·容器
互亿无线明明2 小时前
国际短信通知服务:如何为全球业务构建稳定的跨国消息触达体系?
java·c语言·python·php·objective-c·ruby·composer