热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

NestJs学习之旅(8)——管道

欢迎持续关注NestJs学习之旅系列文章管道熟悉Linux命令的伙伴应该对“管道运算符”不陌生。ls-la|grepdemo“|”就是管道运算符,它把左边命令的输出作为输入传递给右

欢迎持续关注NestJs学习之旅系列文章

《NestJs学习之旅(8)——管道》

管道

熟悉Linux命令的伙伴应该对“管道运算符”不陌生。

ls -la | grep demo

“|” 就是管道运算符,它把左边命令的输出作为输入传递给右边的命令,支持级联,如此一来,便可以通过管道运算符进行复杂命令的交替运算。

《NestJs学习之旅(8)——管道》

NestJs中的管道有着类似的功能,也可以级联处理数据。NestJs管道通过@Injectable()装饰器装饰,需要实现PipeTransform接口。

NestJs中管道的主要职责如下:

  • 数据转换 将输入数据转换为所需的输出
  • 数据验证 接收客户端提交的参数,如果通过验证则继续传递,如果验证未通过则提示错误

执行顺序

在前面的文章中我们讨论了中间件控制器路由守卫,结合本问讨论的管道,可能有些读者会对这些组件的执行顺序提出疑问:这些东西执行的顺序到底是怎样的?

执行顺序也不用找资料,自己在这些组件执行时加上日志即可,我得出的结论如下:

客户端请求 -> 中间件 -> 路由守卫 -> 管道 -> 控制器方法

开发管道

数据转换类的管道就不详细解释了:

给你一个value和元数据,你的return值就是转换后的值。

NestJs内置了ValidationPipe、ParseIntPipe和ParseUUIDPipe。为了更好地理解它们的工作原理,我们以ValidationPipe(验证器管道)为例来演示管道的使用。

PipeTransform

这是管道必须实现的接口,该接口定义如下:

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

  • value 输入参数,T为输入参数类型
  • metadata value的元数据,包括参数来源,参数类型等等
  • 输出参数,R为输出参数类型

ArgumentMetadata

用来描述当前处理value的元数据接口,接口定义如下:

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

这个接口大家可能看不明白,没关系,等下会有具体示例来进行解读。

  • type 输入数据的来源
  • metatype > 注入数据的类型
  • data 传递给装饰器的数据类型

例如如下控制器方法:

@Post()
login(@Query('type') type: number) { // type 为登录类型参数,类似手机号登录为1,账号登录为2的例子
}

上述例子的元数据如下:

  • type query @Query装饰器是读取GET参数
  • metatype Number type的类型符号
  • data type 传递给@Query装饰器的参数为“type”

验证器示例

下面以用户登录时校验账号密码来说明验证器管道的使用,规则如下:

  • 账号必须是字符串,长度6-20
  • 密码不能为空

DTO定义

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 {
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更多的知识,欢迎加群讨论!

《NestJs学习之旅(8)——管道》


推荐阅读
  • 《数据结构》学习笔记3——串匹配算法性能评估
    本文主要讨论串匹配算法的性能评估,包括模式匹配、字符种类数量、算法复杂度等内容。通过借助C++中的头文件和库,可以实现对串的匹配操作。其中蛮力算法的复杂度为O(m*n),通过随机取出长度为m的子串作为模式P,在文本T中进行匹配,统计平均复杂度。对于成功和失败的匹配分别进行测试,分析其平均复杂度。详情请参考相关学习资源。 ... [详细]
  • node.jsurlsearchparamsAPI哎哎哎 ... [详细]
  • 在Android开发中,使用Picasso库可以实现对网络图片的等比例缩放。本文介绍了使用Picasso库进行图片缩放的方法,并提供了具体的代码实现。通过获取图片的宽高,计算目标宽度和高度,并创建新图实现等比例缩放。 ... [详细]
  • 知识图谱——机器大脑中的知识库
    本文介绍了知识图谱在机器大脑中的应用,以及搜索引擎在知识图谱方面的发展。以谷歌知识图谱为例,说明了知识图谱的智能化特点。通过搜索引擎用户可以获取更加智能化的答案,如搜索关键词"Marie Curie",会得到居里夫人的详细信息以及与之相关的历史人物。知识图谱的出现引起了搜索引擎行业的变革,不仅美国的微软必应,中国的百度、搜狗等搜索引擎公司也纷纷推出了自己的知识图谱。 ... [详细]
  • 本文讨论了一个关于cuowu类的问题,作者在使用cuowu类时遇到了错误提示和使用AdjustmentListener的问题。文章提供了16个解决方案,并给出了两个可能导致错误的原因。 ... [详细]
  • JVM 学习总结(三)——对象存活判定算法的两种实现
    本文介绍了垃圾收集器在回收堆内存前确定对象存活的两种算法:引用计数算法和可达性分析算法。引用计数算法通过计数器判定对象是否存活,虽然简单高效,但无法解决循环引用的问题;可达性分析算法通过判断对象是否可达来确定存活对象,是主流的Java虚拟机内存管理算法。 ... [详细]
  • sklearn数据集库中的常用数据集类型介绍
    本文介绍了sklearn数据集库中常用的数据集类型,包括玩具数据集和样本生成器。其中详细介绍了波士顿房价数据集,包含了波士顿506处房屋的13种不同特征以及房屋价格,适用于回归任务。 ... [详细]
  • Python正则表达式学习记录及常用方法
    本文记录了学习Python正则表达式的过程,介绍了re模块的常用方法re.search,并解释了rawstring的作用。正则表达式是一种方便检查字符串匹配模式的工具,通过本文的学习可以掌握Python中使用正则表达式的基本方法。 ... [详细]
  • Python SQLAlchemy库的使用方法详解
    本文详细介绍了Python中使用SQLAlchemy库的方法。首先对SQLAlchemy进行了简介,包括其定义、适用的数据库类型等。然后讨论了SQLAlchemy提供的两种主要使用模式,即SQL表达式语言和ORM。针对不同的需求,给出了选择哪种模式的建议。最后,介绍了连接数据库的方法,包括创建SQLAlchemy引擎和执行SQL语句的接口。 ... [详细]
  • 本文介绍了操作系统的定义和功能,包括操作系统的本质、用户界面以及系统调用的分类。同时还介绍了进程和线程的区别,包括进程和线程的定义和作用。 ... [详细]
  • SpringBoot整合SpringSecurity+JWT实现单点登录
    SpringBoot整合SpringSecurity+JWT实现单点登录,Go语言社区,Golang程序员人脉社 ... [详细]
  • 本文讨论了在ASP中创建RazorFunctions.cshtml文件时出现的问题,即ASP.global_asax不存在于命名空间ASP中。文章提供了解决该问题的代码示例,并详细解释了代码中涉及的关键概念,如HttpContext、Request和RouteData等。通过阅读本文,读者可以了解如何解决该问题并理解相关的ASP概念。 ... [详细]
  • 本文介绍了使用readlink命令获取文件的完整路径的简单方法,并提供了一个示例命令来打印文件的完整路径。共有28种解决方案可供选择。 ... [详细]
  • 2019独角兽企业重金招聘Python工程师标准
    本文介绍了2019独角兽企业对Python工程师的招聘标准,包括在AndroidManifest中定义meta-data的方法和获取meta-data值的代码。同时提供了获取meta-data值的具体实现方法。转载文章链接:https://my.oschina.net/u/244918/blog/685127 ... [详细]
  • 本文介绍了Hive常用命令及其用途,包括列出数据表、显示表字段信息、进入数据库、执行select操作、导出数据到csv文件等。同时还涉及了在AndroidManifest.xml中获取meta-data的value值的方法。 ... [详细]
author-avatar
饿狼传说少校_584_869_541
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有