如何自定义 Pipe?

41 阅读1分钟

Pipe 是在参数传给 Controller 之前做一些验证和转换的,有 多个内置的 Pipe 可以直接用

Nest 一次请求的顺序是:

Middleware
  ↓
Guard
  ↓
Interceptor (before)
  ↓
Pipe   ✅(就在这里)
  ↓
Controller handler
  ↓
Interceptor (after)
  ↓
ExceptionFilter

👉 Pipe 发生在 handler 真正被调用之前,而且是“参数级别”执行

Pipe 的接口定义

export interface PipeTransform<T = any, R = any> {
  transform(value: T, metadata: ArgumentMetadata): R;
}

ArgumentMetadata 是关键:

export interface ArgumentMetadata {
  type: 'body' | 'query' | 'param' | 'custom';
  metatype?: Type<any>;
  data?: string;
}

也就是说,Pipe 能知道:

  • 这个参数来自哪里(body / query / param)
  • DTO 是什么 class
  • 装饰器里写的是 @Body('id') 还是整个 body

内置的 Pipe 有这些:

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

看一下使用

nest new pipe-inner -p npm

ParseIntPipe

image.png

如果可以转正常展示

image.png

如果不可以转 报错

image.png

状态码和信息也可以改

image.png

image.png

可以自己抛一个异常出来,然后让 exception filter 处理

image.png

image.png

ParseFloatPipe 是把参数转换为 float 类型

image.png

image.png

也可以 new ParseFloatPipe 的形式,传入 errorHttpStatusCode 和 exceptionFactory

ParseBoolPipe

image.png

image.png

ParseArrayPipe

image.png

需要安装

image.png

npm install -D class-validator class-transformer

没有转为数字

image.png

指定 item 的类型

这样就把数组每一项处理为 number

image.png

image.png

ParseEnumPipe

image.png

image.png

image.png

参数不是枚举值内

image.png

ParseUUIDPipe

UID 是一种随机生成的几乎不可能重复的字符串,做 id

image.png

image.png

image.png

image.png

不是 uuid 会报错

image.png

DefaultValuePipe 设置默认值

image.png

image.png

实现个 Pipe

自己写一个 pipe 也很简单,实现 PipeTransform 接口的 transform 方法,返回值就是传给 handler 的值

nest g pipe aaa --flat --no-spec

生成一个 pipe,打印下参数值,返回 aaa

image.png

使用

image.png

image.png

返回的值是 aaaaaa,也就是说 pipe 的返回值就是传给 handler 的参数值。

打印的 value 就是 query、param 的值,而 metadata 里包含 type、metatype、data

image.png