【NestJS学习笔记】 之 管道

149 阅读6分钟

前言,小编最近在学习NestJS系列相关知识,想把自己了解到的知识点作为笔记的同时也分享给大家,本篇涉及的是与管道相关的知识,如果有哪里写的不好的话还恳请各位掘友批评指正谢谢,小编将不胜感激,闲话不多说,我们直接步入正题吧...

管道定义

 NestJS的管道是一种用于数据转换和验证的机制。它们是在控制器处理请求之前执行的函数,可以对传入的数据进行处理、验证或转换。
 

微信图片_20240709180222.png

应用场景:

  • 转换:管道将输入数据转换为所需的数据输出(例如,将字符串转换为整数)
  • 验证:对输入数据进行验证,如果验证成功继续传递; 验证失败则抛出异常

看到这里,可能有的小伙伴不清楚管道和过滤器的区别的,别急,听小编给您娓娓道来。NestJS 中的管道(Pipes)和过滤器(Filters)虽然都是用于处理请求的中间件,但它们的功能和使用场景有明显的区别:

1.  主要功能:
    -   管道:主要用于数据转换和验证。
    -   过滤器:主要用于异常处理和响应转换。
2.  执行时机:

    -   管道:在控制器方法执行之前运行。
    -   过滤器:在整个请求-响应周期中,主要在发生异常时执行。

3.  处理对象:

    -   管道:处理输入数据(如请求参数、请求体)。
    -   过滤器:处理抛出的异常。

4.  使用场景:

    -   管道:参数验证、类型转换、数据净化等。
    -   过滤器:统一异常处理、日志记录、自定义错误响应等。

5.  返回值:

    -   管道:返回转换后的数据或原始数据。
    -   过滤器:通常返回一个 HTTP 响应。

6.  绑定方式:

    -   管道:可以绑定到特定的参数、方法、控制器或全局。
    -   过滤器:可以绑定到控制器、模块或全局。

7.  接口实现:

    -   管道:实现 PipeTransform 接口。
    -   过滤器:实现 ExceptionFilter 接口。

内置管道

NestJS提供了一些内置的管道,他们从 @nestjs/common 包中导出。如:

  • ValidationPipe:用于数据验证
  • ParseIntPipe:将字符串解析为整数
  • ParseBoolPipe:将字符串解析为布尔值
  • ParseArrayPipe:将字符串解析为数组
  • ParseUUIDPipe:验证并转换UUID字符串

绑定管道与验证(这里使用ParseIntPipe,尝试将字符串解析为整数)

微信图片_20240709162500.png

微信图片_20240709162538.png

微信图片_20240709162542.png

在上述例子中,我们传递了一个类(ParseIntPipe),而不是一个实例,将实例化留给框架去处理,做到了依赖注入。对于管道和守卫,我们也可以选择传递一个实例。如果我们想通过传递选项来自定义内置管道的行为,传递实例很有用:

@Get(':id')
async findOne(
  @Param('id', new ParseIntPipe({ errorHttpStatusCode: HttpStatus.NOT_ACCEPTABLE }))
  id: number,
) {
  return this.catsService.findOne(id);
}

自定义管道

虽然 Nest 提供了强大的内置 ParseIntPipe 和 ValidationPipe,但让我们从头开始构建它们的简单自定义版本,以了解如何构建自定义管道。先从一个简单的 ValidationPipe 开始。最初,我们让它接受一个输入值并立即返回相同的值。

微信图片_20240709164941.png

上图使用ctrl + 单击 PipeTransform 接口即可进入下图:

微信图片_20240709164945.png

说明:

为实现 PipeTransfrom,每个管道必须声明 transfrom() 方法。该方法有两个参数:

  • value
  • metadata value 参数是当前处理的方法参数(在被路由处理程序方法接收之前),metadata 是当前处理的方法参数的元数据。元数据对象具有以下属性:
export interface ArgumentMetadata {
  type: 'body' | 'query' | 'param' | 'custom';
  metatype?: Type<unknown>;
  data?: string;
}

这些属性描述了当前处理的参数。

参数描述
type告诉我们参数是一个 body @Body(),query @Query(),param @Param() 还是自定义参数
metatype参数的元类型,例如 String。 如果在函数签名中省略类型声明,或者使用原生 JavaScript,则为 undefined
data传递给装饰器的字符串,例如 @Body('string')。如果您将括号留空,则为 undefined

使用管道实现验证DTO

创建验证管道

 nest g pipe 管道名称

微信图片_20240709170238.png

使用类验证器:Nest 与 class-validator 配合得很好。这个优秀的库允许我们使用基于装饰器的验证。装饰器的功能非常强大,尤其是与 Nest 的 Pipe 功能相结合使用时,因为我们可以通过访问 metatype 信息做很多事情,在开始之前需要安装一些依赖

 npm i --save class-validator class-transformer

安装完成后,我们就可以向 CreateCatDto 类添加一些装饰器。在这里,我们看到了这种技术实现的一个显著优势:CreateCatDto 类仍然是我们的 Post body 对象的单一可靠来源(而不是必须创建一个单独的验证类)。

微信图片_20240709171132.png

现在我们来创建一个 ValidationPipe 类。

微信图片_20240709172259.png

transform() 函数是 异步 的, Nest 支持同步异步管道。这样做的原因是因为有些 class-validator 的验证是可以异步的(利用 Promise)

接下来请注意,我们正在使用解构赋值提取 metatype 字段(只从 ArgumentMetadata 中提取了该成员)赋值给 metatype 参数。这是一个先获取全部 ArgumentMetadata 然后用附加语句提取某个变量的简写方式。

下一步,请观察 toValidate() 方法。当正在处理的参数是原生 JavaScript 类型时,它负责绕过验证步骤(它们不能附加验证装饰器,因此没有理由通过验证步骤运行它们)。

下一步,我们使用 class-transformer 的 plainToInstance() 方法将普通的 JavaScript 参数对象转换为可验证的类型对象。必须这样做的原因是传入的 post body 对象在从网络请求反序列化时不携带任何类型信息(这是底层平台(例如 Express)的工作方式)。 Class-validator 需要使用我们之前为 DTO 定义的验证装饰器,因此我们需要执行此转换,将传入的主体转换为有装饰器的对象,而不仅仅是普通的对象。

最后,如前所述,这就是一个验证管道,它要么返回值不变,要么抛出异常。

接下来就可以绑定 ValidationPipe,示例如下(检验post body):

微信图片_20240709173219.png

微信图片_20240709173558.png

微信图片_20240709175829.png

全局管道

由于 ValidationPipe 被创建为尽可能通用,所以我们将把它设置为一个全局作用域的管道,用于整个应用程序中的每个路由处理器。

微信图片_20240709173911.png

以上就是小编对于NestJS中管道的知识点的理解,感谢阅读!!!