欢迎持续关注NestJs学习之旅系列文章typescript
熟悉Linux命令的伙伴应该对“管道运算符”不陌生。npm
ls -la | grep demo
"|" 就是管道运算符,它把左边命令的输出做为输入传递给右边的命令,支持级联,如此一来,即可以经过管道运算符进行复杂命令的交替运算。json
NestJs中的管道有着相似的功能,也能够级联处理数据。NestJs管道经过@Injectable()装饰器装饰,须要实现PipeTransform接口。bootstrap
NestJs中管道的主要职责以下:bash
在前面的文章中咱们讨论了中间件、控制器、路由守卫,结合本问讨论的管道,可能有些读者会对这些组件的执行顺序提出疑问:这些东西执行的顺序究竟是怎样的?app
执行顺序也不用找资料,本身在这些组件执行时加上日志便可,我得出的结论以下:框架
客户端请求 -> 中间件 -> 路由守卫 -> 管道 -> 控制器方法
数据转换类的管道就不详细解释了:async
给你一个value和元数据,你的return值就是转换后的值。
NestJs内置了ValidationPipe、ParseIntPipe和ParseUUIDPipe。为了更好地理解它们的工做原理,咱们以ValidationPipe(验证器管道)为例来演示管道的使用。学习
这是管道必须实现的接口,该接口定义以下:this
export interface PipeTransform<T = any, R = any> { transform(value: T, metadata: ArgumentMetadata): R; }
用来描述当前处理value的元数据接口,接口定义以下:
export interface ArgumentMetadata { readonly type: 'body' | 'query' | 'param' | 'custom'; readonly metatype?: Type<any>; readonly data?: string; }
这个接口你们可能看不明白,不要紧,等下会有具体示例来进行解读。
例如以下控制器方法:
@Post() login(@Query('type') type: number) { // type 为登陆类型参数,相似手机号登陆为1,帐号登陆为2的例子 }
上述例子的元数据以下:
下面以用户登陆时校验帐号密码来讲明验证器管道的使用,规则以下:
DTO在Java中是Data Transfer Object,简单来讲就是对数据的一层包装。我们NestJs中用这个东西通常是为了防止非法字段的提交和IDE自动提示(偷笑)。
使用规则装饰器须要安装class-validator和class-transformer:
npm i --save class-validator class-transformer
登陆表单定义以下:
// userLogin.dto.ts export class UserLoginDto { @IsString() @Length(6, 20, { message: '长度不合法' }) readonly username: string; @Length(1) readonly password: string; }
因为我们的管道是通用的,也就是验证什么内容是由外部决定的,管道只负责“你给我数据和规则,我来校验”。因此我们须要使用到装饰器元数据。
// validate.pipe.ts import { ArgumentMetadata, BadRequestException, Injectable, PipeTransform } from '@nestjs/common'; import { plainToClass } from 'class-transformer'; import { validate } from 'class-validator'; @Injectable() export class ValidatePipe implements PipeTransform { async transform(value: any, { metatype }: ArgumentMetadata): Promise<any> { if (!metatype || !this.toValidate(metatype)) { // 若是不是注入的数据且不须要验证,直接跳过处理 return value; } // 数据格式转换 const object = plainToClass(metatype, value); // 调用验证 const errors = await validate(object); // 若是错误长度大于0,证实出错,须要抛出400错误 if (errors.length > 0) { throw new BadRequestException(errors); } return value; } /** * 须要验证的数据类型 * @param metatype */ private toValidate(metatype: any): boolean { const types = [String, Boolean, Number, Array, Object]; return !types.includes(metatype); } }
今天的主角是管道,因此控制器层就不写逻辑了
// user.controller.ts @Post('login') @UsePipes(ValidatePipe) login(@Body() userLoginDto: UserLoginDTO) { return {errcode:0, errmsg: 'ok'}; }
项目根目录执行如下命令便可运行NestJs项目:
npm run start
项目运行后可使用Postman来验证一下:
请求数据1
{ }
响应数据1
{ "statusCode": 400, "error": "Bad Request", "message": [ { "target": {}, "property": "username", "children": [], "constraints": { "length": "长度不合法", "isString": "username must be a string" } }, { "target": {}, "property": "password", "children": [], "constraints": { "length": "password must be longer than or equal to 1 characters" } } ] }
请求数据2
{ "username":"xialeistudio" }
响应数据2
{ "statusCode": 400, "error": "Bad Request", "message": [ { "target": { "username": "xialeistudio" }, "property": "password", "children": [], "constraints": { "length": "password must be longer than or equal to 1 characters" } } ] }
请求数据3
{ "username":"xialeistudio", "password":"111111" }
响应数据3
[]
上文演示了ValidatePipe的实现,生产环境直接使用NestJs提供的ValidationPipe便可。咱们能够在main.ts中使用全局管道。
async function bootstrap() { const app = await NestFactory.create(AppModule); app.useGlobalPipes(new ValidationPipe()); await app.listen(3000); } bootstrap();
和笔者使用的SpringBoot中验证框架对比一下以后发现,NestJs验证管道所实现的功能还真不比SpringBoot差,看来官方说的“下一代Node.js全栈开发框架”确实不是盖的!
若是您以为有所收获,分享给更多须要的朋友,谢谢!
若是您想交流关于NestJs更多的知识,欢迎加群讨论!