NestJS博客实战11-管道验证与转换

1,028 阅读6分钟
by 雪隐 from https://juejin.cn/user/1433418895994094
本文欢迎分享与聚合,全文转载就不必了,尊重版权,圈子就这么大,若急用可联系授权

大家好,让大家久等了!这一章介绍一下管道验证与数据转换相关的内容。

我们通过http请求的数据发送服务器里面接收到的,一般是没有类型或者全是字符串类型的数据。这样我们处理业务逻辑的时候,不得不对这些数据进行一一的转换。如果项目非常庞大这种操作无疑要很大的工作量。幸好NestJS中提供了数据转换和验证支持,能够让我们更加轻松的完成这些工作。

管道

在NestJS中,管道(Pipes)是一种用于处理输入数据的机制。管道允许你对进入应用程序的数据进行转换、验证和转变。它们是NestJS中的一种重要概念,用于帮助保证输入数据的有效性和一致性。

NestJS提供了多种类型的管道,包括:

  1. 转换管道(Transformation Pipes):这些管道用于将输入数据转换为期望的格式。例如,你可以使用ParseIntPipe将字符串转换为整数类型。
  2. 验证管道(Validation Pipes):这些管道用于验证输入数据是否符合特定的规则或条件。NestJS内置了一些常用的验证器,如IsNotEmpty、IsString、IsNumber等,你也可以自定义验证器。
  3. 异常管道(Exception Pipes):这些管道用于处理发生的异常。你可以创建一个自定义的异常过滤器来捕获并处理抛出的异常。
  4. 自定义管道(Custom Pipes):你可以根据需要创建自定义管道来实现特定的逻辑。自定义管道可以用于数据转换、验证或者执行其他操作。

使用管道非常简单,你只需在处理器(Controller)或者参数的装饰器上应用管道即可。例如,你可以在一个路由处理器方法上使用管道来验证请求体

@Post()
@UsePipes(new ValidationPipe())
create(@Body() data: CreateDto) {
  // 处理请求
}

在上面的示例中,ValidationPipe被应用于create方法的参数data上,它将验证请求体是否符合CreateDto定义的规则。

管道是NestJS中用于处理输入数据的强大工具,可以帮助你确保数据的有效性和一致性,同时提高代码的可维护性。

优缺点

管道在NestJS中作为数据处理的机制具有一些优点和缺点,让我们看一下它们:

优点:

  1. 代码重用:使用管道可以将通用的数据转换和验证逻辑封装起来,以便在应用程序的多个地方重用。这样可以减少重复的代码编写,提高代码的可维护性和可读性。
  2. 数据验证:管道提供了内置的验证器和自定义验证器的功能,可以帮助你验证输入数据是否符合预期的规则和约束。这样可以确保数据的有效性和一致性,减少了错误数据进入应用程序的可能性。
  3. 数据转换:管道还可以对输入数据进行转换和格式化,将其转换为应用程序所需的特定格式。这对于处理输入数据的一致性和可靠性非常有用,尤其是当你需要将不同数据类型进行转换时。
  4. 异常处理:通过异常管道,你可以捕获并处理抛出的异常。这样可以集中处理错误和异常情况,提高应用程序的可靠性,并提供更好的错误处理机制。

缺点:

  1. 复杂性增加:引入管道机制可能会增加一定的复杂性,特别是对于较大的应用程序或者复杂的数据处理逻辑。需要合理地设计和组织管道,以确保其可维护性和可扩展性。
  2. 性能开销:管道涉及对输入数据的处理和转换,这可能会带来一些性能开销。尤其是在处理大量数据或者复杂的转换逻辑时,需要考虑性能方面的影响。
  3. 学习曲线:理解和使用管道机制可能需要一定的学习曲线,特别是对于新手来说。需要了解不同类型的管道、如何创建和应用它们,以及如何处理错误和异常情况。

尽管存在一些缺点,但管道作为NestJS的核心特性,仍然是一个强大而有用的工具,可以帮助你处理和保护输入数据,提高应用程序的质量和可靠性。

管道验证

官方推荐了2种验证方式,我选用class-transformer,class-validator的方式,这种方式在NestJs中被支持的很好,接下来就把管道安排到项目中来

  1. 首先安装依赖。
pnpm i class-transformer class-validator
  1. 修改dto文件

让我们修改下创建用户的Dto文件。 对每一个属性添加注解,这些注解会自动进行数据转换。如果转换失败,则会进入异常的流程。

  • create-user.dto.ts
import { IsString, IsIn } from 'class-validator';

export class CreateUserDto {
  @IsString()
  userid: string;
  @IsString()
  password: string;
  @IsString()
  username: string;
  @IsIn([0, 1])
  status: number;
}
  1. main.ts中加入全局管道验证 可以自己写管道验证,这里我使用内置的验证管道,并把它注册到全局。
import { ValidationPipe } from '@nestjs/common';

async function bootstrap() {
  const app = await NestFactory.create<NestFastifyApplication>(
    AppModule,
    new FastifyAdapter(),
  );

  // 全局验证管道
  app.useGlobalPipes(new ValidationPipe());
  
  ...
  
  await app.listen(serverValue.port, serverValue.host);
}
bootstrap();
  1. 另外还有许多内置的转换验证依赖 对于一些,参数比较少的接口,不必要写成Dto形式,可以简单的利用内置的验证管道达到同样的效果。
  • ValidationPipe
  • ParseIntPipe
  • ParseFloatPipe
  • ParseBoolPipe
  • ParseArrayPipe
  • ParseUUIDPipe
  • ParseEnumPipe
  • DefaultValuePipe
  • ParseFilePipe

gossip.controller.ts

  @Get('gossip/:id')
  async findGossip(@Param('id', ParseIntPipe) id: number) {
    return await this.gossipService.findById(id);
  }
  1. 测试看效果

通过下面的命令运行项目,并启动vsCode的调试模式。

npm run start:debug

先请求一个错误的类型试试,这里把status改成字符串类型的1,然后请求发现抱错

image.png

在创建用户controller里面加入一个断点

用postman来请求创建用户的接口,在断点停住的地方来查看类型。可以看到status被正确的转换为数字类型。

image.png

image.png

白名单

另外很多时候,前端传给后端数据的时候,会有垃圾数据。后端在处理数据的时候会由于这些垃圾数据而导致异常的情况。所以可以设置whitelisttrue,这样只有用到class-validator里面的注解的属性才能被允许传入接口。我推荐大家要设置这个属性。

  // 全局验证管道
  app.useGlobalPipes(new ValidationPipe({ whitelist: true }));

还是拿创建用户的接口举例:

image.png

image.png

在请求的时候增加了一个otherProp,请求的的时候查看断点上的Dto时,这个属性已经被过滤掉了。

如果您觉得这篇文章对您有帮助别忘了点赞/评论。谢谢大家🙏!

本章代码

代码