管道
管道
管道是用 @Injectable() 装饰器注释的类,它实现了 PipeTransform 接口

管道有两个典型的用例:
- 转型:将输入数据转换为所需的形式(例如,从字符串到整数)
- 验证:评估输入数据,如果有效,只需将其原样传递;否则抛出异常
在这两种情况下,管道都在由 控制器路由处理器 处理的 arguments 上运行。Nest 在调用方法之前插入一个管道,管道接收指定给该方法的参数并对它们进行操作。任何转换或验证操作都会在此时发生,之后会使用任何(可能)转换的参数调用路由处理程序。
Nest 附带了许多内置管道,你可以开箱即用。你还可以构建自己的自定义管道。在本章中,我们将介绍内置管道并展示如何将它们绑定到路由处理程序。然后,我们将检查几个定制的管道,以展示如何从头开始构建一个。
注意
管道在例外区域内运行。这意味着当 Pipe 抛出异常时,它由异常层处理(全局异常过滤器和应用于当前上下文的任何 异常过滤器)。综上所述,应该很清楚,当在 Pipe 中抛出异常时,随后不会执行任何控制器方法。这为你提供了一种最佳实践技术,用于在系统边界验证从外部源进入应用的数据。
内置管道
Nest 提供了几个内置的管道,你可以开箱即用。这些管道在 @nestjs/common 包中定义。
Nest 附带几个开箱即用的管道:
- ValidationPipe:验证输入数据
- ParseIntPipe:将输入数据转换为整数
- ParseFloatPipe:将输入数据转换为浮点数
- ParseBoolPipe:将输入数据转换为布尔值
- ParseArrayPipe:将输入数据转换为数组
- ParseUUIDPipe:将输入数据转换为 UUID
- ParseEnumPipe:将输入数据转换为枚举
- DefaultValuePipe:设置默认值
- ParseFilePipe:将输入数据转换为文件
- ParseDatePipe:将输入数据转换为日期
它们是从 @nestjs/common 包中导出的。
让我们快速浏览一下 ParseIntPipe 的使用。这是转换用例的示例,其中管道确保方法处理程序参数转换为 JavaScript 整数
// app.controller.ts
import { Controller, Get, Param, ParseIntPipe } from '@nestjs/common';
import { AppService } from './app.service';
@Controller()
export class AppController {
constructor(private readonly appService: AppService) {}
@Get(':id')
async getHello(@Param('id',ParseIntPipe) id: number) {
return this.appService.getHello(id);
}
}引入app.service.ts中的getHello方法,返回id的值
// app.service.ts
import { Injectable } from '@nestjs/common';
@Injectable()
export class AppService {
getHello(id): number {
return id;
}
}这确保以下两个条件之一为真:我们在 getHello() 方法中收到的参数是一个数字(正如我们对 this.appService.getHello() 的调用所预期的那样),或者在调用路由处理程序之前抛出异常。
例如,假设路由被称为:http://127.0.0.1:3000/aaa
Nest 会抛出这样的异常

该异常将阻止 getHello() 方法的主体执行
例如,假设路由被称为:http://127.0.0.1:3000/12345
Nest 执行 getHello() 方法的主体,并返回以下 JSON 响应:

在上面的示例中,我们传递了一个类 (ParseIntPipe),而不是一个实例,将实例化的责任留给了框架并启用依赖注入。与管道和守卫一样,我们可以传递一个就地实例。如果我们想通过传递选项来自定义内置管道的行为,那么传递就地实例很有用:
// app.controller.ts
import { Controller, Get, HttpStatus, Param, ParseIntPipe } from '@nestjs/common';
import { AppService } from './app.service';
@Controller()
export class AppController {
constructor(private readonly appService: AppService) {}
@Get(':id')
// NOT_ACCEPTABLE 对应的状态码是 406,当传入的 id 不是数字时,会抛出一个 406 错误。
async getHello(@Param('id',new ParseIntPipe({errorHttpStatusCode:HttpStatus.NOT_ACCEPTABLE})) id: number) {
return this.appService.getHello(id);
}
}当传入的 id 不是数字时,会抛出一个 406 错误

绑定其他转换管道(所有 Parse* 管道)的工作原理类似。这些管道都在验证路由参数、查询字符串参数和请求正文值的上下文中工作。
例如,使用查询字符串参数:
// app.controller.ts
import { Controller, Get, HttpStatus, Param, ParseIntPipe, Query } from '@nestjs/common';
import { AppService } from './app.service';
@Controller()
export class AppController {
constructor(private readonly appService: AppService) {}
@Get()
async getHello(@Query('id',ParseIntPipe) id: number) {
return this.appService.getHello(id);
}
}执行如下:

绑定验证管道
我们使用 @UsePipes() 装饰器来做到这一点,如下所示:
@Post()
@UsePipes(new ZodValidationPipe(createCatSchema))
async create(@Body() createCatDto: CreateCatDto) {
this.catsService.create(createCatDto);
}在上面的示例中,我们使用 ZodValidationPipe 来验证请求体。ZodValidationPipe 是一个自定义管道,它使用 Zod 库来验证请求体。
注意:上面的管道是自定义管道,我在这里没有给出对应的教程,有兴趣的可以自行去了解。
注意
@UsePipes() 装饰器是从 @nestjs/common 包导入的
zod 库需要在 tsconfig.json 文件中启用 strictNullChecks 配置。
