Nest.js系列——内置 Pipe 和自定义 Pipe

在 NestJS 框架中,Pipe 是一个强大的功能,用于在请求处理程序执行之前验证和转换数据。就是在参数传递到处理函数之前做一些验证和转换处理的 class,NestJS 内置了一系列常用的 Pipe,并且允许开发者根据需求创建自定义 Pipe。下面我们将介绍各种内置 Pipe 的使用例子,并展示如何实现一个自定义 Pipe。内置的 Pipe 有这些:

  • ValidationPipe
  • ParseIntPipe
  • ParseBoolPipe
  • ParseArrayPipe
  • ParseUUIDPipe
  • ParseEnumPipe
  • ParseFilePipe
  • ParseFloatPipe
  • DefaultValuePipe

ValidationPipe

在 NestJS 中,ValidationPipe 用于自动执行输入数据验证。这通常与类类型 (DTO - Data Transfer Objects) 一起使用。一般依赖与两个库来实现class-validatorclass-transformer.

class-validatorclass-transformer 是两个在 TypeScriptJavaScript 项目中经常联合使用的库,它们提供了一套装饰器和一些函数来实现数据的验证和转换功能。在许多服务器端框架中,尤其是在 NestJS 中,这两个库用来处理和验证客户端发送到服务器的数据并进行类型转换。

在项目中一般会全局开启这个管道来对数据进行验证

ts 复制代码
// 全局管道
app.useGlobalPipes(new ValidationPipe())

ParseIntPipe

在路由中拿参数一般情况下是 string 类型,ParseIntPipe就对拿到的数据进行转换,简单的用法就是直接在控制器方法中添加管道

ts 复制代码
@Get()
  getHello(@Query('water', ParseIntPipe) water: string): string {
    return water;
  }

通过这个管道,可以将字符串类型的参数转化为数字类型

如果传递的参数是不能转化为数字类型的话,那么就是会报错了。 可以看到这里的错误吗是 400,其实这个错误码是可以更改的,改变下管道的调用方式加一些参数。

ts 复制代码
@Get('water')
  getWater(
    @Query(
      'water',
      new ParseIntPipe({
        errorHttpStatusCode: HttpStatus.NOT_FOUND,
      }),
    )
    water: string,
  ): string {
    return water;
  }

然后调用下这个接口,看下返回结果是什么 由图中可以看出状态码已经更改为 404 了。当然也可以直接抛出一个错误,让过滤器去拦截,或者使用自定义过滤器处理。

ts 复制代码
@Get('error')
  getError(
    @Query(
      'water',
      new ParseIntPipe({
        exceptionFactory(error) {
          console.log(error);
          throw new HttpException('xxx ' + error, HttpStatus.NOT_IMPLEMENTED);
        },
      }),
    )
    water: string,
  ): string {
    return water;
  }

在调用下就能看到错误信息已经改变

ParseFloatPipe

这个管道是转换为浮点数的,可以使用下看看效果

ts 复制代码
@Get('water-float')
  getFloat(@Query('water', ParseFloatPipe) water: number) {
    return water + 2;
  }

看下访问的结果 类型为字符串的参数被转换为浮点数并做了计算。

ParseBoolPipe

通过这个管道把参数值转换为布尔值

ts 复制代码
@Get('water-bool')
  getBool(@Query('water', ParseBoolPipe) water: boolean) {
    return water;
  }

但是能转换的值有限只接受严格的'true'、'false',其他传入的参数会报错

ParseArrayPipe

这个管道会把传入的参数按照一定的规则解析成数组类型,但是这个依赖class-validatorclass-transformer这两个包,前面已经安装过了。

ts 复制代码
@Get('water-arr')
  getArr(
    @Query(
      'water',
      new ParseArrayPipe({
        items: Number,
      }),
    )
    water: Array<number>,
  ) {
    return water;
  }

调用这个接口传入参数看返回的解析后结果

这里使用的时候可以看到,传入了一个参数为items: Number,其实这个就是把数组的每个元素设置为数字,如果不设置这个参数的话返回的会是字符串数组,来实验一下,

ts 复制代码
@Get('water-arr')
  getArr(
    @Query(
      'water',
      ParseArrayPipe
    )
    water: Array<number>,
  ) {
    return water;
  }

再次访问下,看返回结果:

但是这里,还有个问题,如果不传参数就会报错,其实也是有配置可以解决的,配置一下

ts 复制代码
@Get('water-arr')
  getArr(
    @Query(
      'water',
      new ParseArrayPipe({
        items: Number,
        optional: true,
      }),
    )
    water: Array<number>,
  ) {
    return water;
  }

这样就不会报错了,但是解析数组有时候还会有一种情况,比如前后端约定转换时候不是安装,来进行切割的,比如按照;那就需要有改变,这里也是支持指定的,来配置一下

ts 复制代码
@Get('water-arr')
getArr(
  @Query(
    'water',
    new ParseArrayPipe({
      items: Number,
      separator: ';',
      optional: true,
    }),
  )
water: Array<number>,
) {
  return water;
}

调用下看返回结果

ParseUUIDPipe

这个就比较简单了,可以转换判断下参数是不是 uuid

ts 复制代码
@Get('water-uuid')
  getUuid(@Query('water', ParseUUIDPipe) water: string) {
    return water;
  }

ParseEnumPipe

这个管道可以限制传递的参数必须是枚举中的值,如果不是就会报错

ts 复制代码
enum E {
  AAA = '111',
}
@Get('water-enmu')
  getEnmu(@Query('water', new ParseEnumPipe(E)) water: E) {
    return water;
  }

DefaultValuePipe

这个管道可以用来设置默认值,如果没有没有传递任何参数那么就用默认值

ts 复制代码
@Get('water-df')
  getDf(@Query('water', new DefaultValuePipe('water')) water: string) {
    return water;
  }

如果有参数则使用传递的参数

自定义 pipe

以上就是这些内置的 pipe,可以满足一些日常使用,但是很显然,有时候有一些特殊的需求需要自定义一些 pipe,这里就简单写一个自定义的 pipe,先了解如何定义一个自定义的 pipe。先使用 cli 自带的命令创建一个自定义的 pipe。

shell 复制代码
nest g pipe custom-pipe --flat --no-spec

这个命令会在项目根目录下生成一个 pipe 文件

shell 复制代码
- custom-pipe.pipe.ts

默认生成一个简单的 pipe 代码

ts 复制代码
import { ArgumentMetadata, Injectable, PipeTransform } from '@nestjs/common'

@Injectable()
export class CustomPipePipe implements PipeTransform {
  transform(value: any, metadata: ArgumentMetadata) {
    console.log(value, metadata)

    return value
  }
}

这里面加了一行打印日志,看一看接受的内容是什么,然后先写一个接口调用下这个自定义的 pipe。

ts 复制代码
import { CustomPipePipe } from './custom-pipe.pipe';

@Get('custom-pipe')
  getCustomPipe(@Query('water', CustomPipePipe) water: string) {
    return water;
  }

调用下这个接口,看看返回值

再来看看自定义的 pipe 中答应的 log 是什么

由以上可以看出,pipe 中能够获取到请求参数的类型,和获取参数的方式以及参数的值,在这个里面做一些自定义的操作就行了。这就是一个简单的自定义 pipe。

小结

这里简单介绍了 nest 中内置的 pipe 和简单实现了一个自定义的 pipe,这样能够对 pipe 的工作方式有一个自己的理解,希望这个文章对你有帮助,多谢支持。

相关推荐
zopple5 小时前
常见的 Spring 项目目录结构
java·后端·spring
子兮曰6 小时前
Bun v1.3.11 官方更新全整理:新增功能、关键修复与升级验证
javascript·node.js·bun
cjy0001117 小时前
springboot的 nacos 配置获取不到导致启动失败及日志不输出问题
java·spring boot·后端
小江的记录本8 小时前
【事务】Spring Framework核心——事务管理:ACID特性、隔离级别、传播行为、@Transactional底层原理、失效场景
java·数据库·分布式·后端·sql·spring·面试
sheji34168 小时前
【开题答辩全过程】以 基于springboot的校园失物招领系统为例,包含答辩的问题和答案
java·spring boot·后端
程序员cxuan8 小时前
人麻了,谁把我 ssh 干没了
人工智能·后端·程序员
wuyikeer9 小时前
Spring Framework 中文官方文档
java·后端·spring
Victor3569 小时前
MongoDB(61)如何避免大文档带来的性能问题?
后端
Victor3569 小时前
MongoDB(62)如何避免锁定问题?
后端
wuyikeer10 小时前
Spring BOOT 启动参数
java·spring boot·后端