歡迎持續關注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更多的知識,歡迎加羣討論!