成人国产在线小视频_日韩寡妇人妻调教在线播放_色成人www永久在线观看_2018国产精品久久_亚洲欧美高清在线30p_亚洲少妇综合一区_黄色在线播放国产_亚洲另类技巧小说校园_国产主播xx日韩_a级毛片在线免费

資訊專欄INFORMATION COLUMN

從Express到Nestjs,談?wù)凬estjs的設(shè)計(jì)思想和使用方法

chanjarster / 3162人閱讀

摘要:三的洋蔥模型這里簡(jiǎn)單講講在中是如何分層的,也就是說(shuō)請(qǐng)求到達(dá)服務(wù)端后如何層層處理,直到響應(yīng)請(qǐng)求并將結(jié)果返回客戶端。從而使得端支持跨域等。

??最近已經(jīng)使用過(guò)一段時(shí)間的nestjs,讓人寫著有一種java spring的感覺,nestjs可以使用express的所有中間件,此外完美的支持typescript,與數(shù)據(jù)庫(kù)關(guān)系映射typeorm配合使用可以快速的編寫一個(gè)接口網(wǎng)關(guān)。本文會(huì)介紹一下作為一款企業(yè)級(jí)的node框架的特點(diǎn)和優(yōu)點(diǎn)。

從依賴注入(DI)談起

裝飾器和注解

nestjs的“洋蔥模型”

nestjs的特點(diǎn)總結(jié)

原文在我的博客中: https://github.com/forthealll...

歡迎star和fork

一、從依賴注入(DI)談起 (1)、angular中的依賴注入

??從angular1.x開始,實(shí)現(xiàn)了依賴注入或者說(shuō)控制反轉(zhuǎn)的模式,angular1.x中就有controller(控制器)、service(服務(wù)),模塊(module)。筆者在早年間寫過(guò)一段時(shí)間的angular1.3,下面舉例來(lái)說(shuō)明:

var myapp=angular.module("myapp",["ui.router"]);
myapp.controller("test1",function($scope,$timeout){}
myapp.controller("test2",function($scope,$state){}

??上面這個(gè)就是angular1.3中的一個(gè)依賴注入的例子,首先定義了模塊名為“myapp”的module, 接著在myapp這個(gè)模塊中定義controller控制器。將myapp模塊的控制權(quán)交給了myapp.controller函數(shù)。具體的依賴注入的流程圖如下所示:

myapp這個(gè)模塊如何定義,由于它的兩個(gè)控制器決定,此外在控制器中又依賴于$scope、$timeout等服務(wù)。這樣就實(shí)現(xiàn)了依賴注入,或者說(shuō)控制反轉(zhuǎn)。

(2)、什么是依賴注入

??用一個(gè)例子來(lái)通俗的講講什么是依賴注入。

class Cat(){

}
class Tiger(){

}
class Zoo(){
  constructor(){
     this.tiger = new Tiger();
     this.cat = new Cat();
  }
}

??上述的例子中,我們定義Zoo,在其constructor的方法中進(jìn)行對(duì)于Cat和Tiger的實(shí)例化,此時(shí)如果我們要為Zoo增加一個(gè)實(shí)例變量,比如去修改Zoo類本身,比如我們現(xiàn)在想為Zoo類增加一個(gè)Fish類的實(shí)例變量:

class Fish(){}

class Zoo(){
  constructor(){
     this.tiger = new Tiger();
     this.cat = new Cat();
     this.fish = new Fish();
  }
}

??此外如果我們要修改在Zoo中實(shí)例化時(shí),傳入Tiger和Cat類的變量,也必須在Zoo類上修改。這種反反復(fù)復(fù)的修改會(huì)使得Zoo類并沒有通用性,使得Zoo類的功能需要反復(fù)測(cè)試。

我們?cè)O(shè)想將實(shí)例化的過(guò)程以參數(shù)的形式傳遞給Zoo類:

class Zoo(){
  constructor(options){
     this.options = options;
  }
}
var zoo = new Zoo({
  tiger: new Tiger(),
  cat: new Cat(),
  fish: new Fish()
})

??我們將實(shí)力化的過(guò)程放入?yún)?shù)中,傳入給Zoo的構(gòu)造函數(shù),這樣我們就不用在Zoo類中反復(fù)的去修改代碼。這是一個(gè)簡(jiǎn)單的介紹依賴注入的例子,更為完全使用依賴注入的可以為Zoo類增加靜態(tài)方法和靜態(tài)屬性:

class Zoo(){
  static animals = [];
  constructor(options){
     this.options = options;
     this.init();
  }
  init(){
    let _this = this;
    animals.forEach(function(item){
      item.call(_this,options);
    })
  }
  static use(module){
     animals.push([...module])
  }
}
Zoo.use[Cat,Tiger,Fish];
var zoo = new Zoo(options);

??上述我們用Zoo的靜態(tài)方法use往Zoo類中注入Cat、Tiger、Fish模塊,將Zoo的具體實(shí)現(xiàn)移交給了Cat和Tiger和Fish模塊,以及構(gòu)造函數(shù)中傳入的options參數(shù)。

(3)、nestjs中的依賴注入

??在nestjs中也參考了angular中的依賴注入的思想,也是用module、controller和service。

@Module({
  imports:[otherModule],
  providers:[SaveService],
  controllers:[SaveController,SaveExtroController]
})
export class SaveModule {}

??上面就是nestjs中如何定一個(gè)module,在imports屬性中可以注入其他模塊,在prividers注入相應(yīng)的在控制器中需要用到的service,在控制器中注入需要的controller。

二、裝飾器和注解

??在nestjs中,完美的擁抱了typescript,特別是大量的使用裝飾器和注解,對(duì)于裝飾器和注解的理解可以參考我的這篇文章:Typescript中的裝飾器和注解。我們來(lái)看使用了裝飾器和注解后,在nestjs中編寫業(yè)務(wù)代碼有多么的簡(jiǎn)潔:

import { Controller, Get, Req, Res } from "@nestjs/common";

@Controller("cats")

export class CatsController {
  @Get()
  findAll(@Req() req,@Res() res) {
    return "This action returns all cats";
  }
}

??上述定義兩個(gè)一個(gè)處理url為“/cats”的控制器,對(duì)于這個(gè)路由的get方法,定義了findAll函數(shù)。當(dāng)以get方法,請(qǐng)求/cats的時(shí)候,就會(huì)主動(dòng)的觸發(fā)findAll函數(shù)。

??此外在findAll函數(shù)中,通過(guò)req和res參數(shù),在主題內(nèi)也可以直接使用請(qǐng)求request以及對(duì)于請(qǐng)求的響應(yīng)response。比如我們通過(guò)req上來(lái)獲取請(qǐng)求的參數(shù),以及通過(guò)res.send來(lái)返回請(qǐng)求結(jié)果。

三、nestjs的“洋蔥模型”

??這里簡(jiǎn)單講講在nestjs中是如何分層的,也就是說(shuō)請(qǐng)求到達(dá)服務(wù)端后如何層層處理,直到響應(yīng)請(qǐng)求并將結(jié)果返回客戶端。

在nestjs中在service的基礎(chǔ)上,按處理的層次補(bǔ)充了中間件(middleware)、異常處理(Exception filters)、管道(Pipes),守衛(wèi)(Guards),以及攔截器(interceptors)在請(qǐng)求到打真正的處理函數(shù)之間進(jìn)行了層層的處理。

上圖中的邏輯就是分層處理的過(guò)程,經(jīng)過(guò)分層的處理請(qǐng)求才能到達(dá)服務(wù)端處理函數(shù),下面我們來(lái)介紹nestjs中的層層模型的具體作用。

(1)、middleware中間件

??在nestjs中的middle完全跟express的中間件一摸一樣。不僅如此,我們還可以直接使用express中的中間件,比如在我的應(yīng)用中需要處理core跨域:

import * as cors from "cors";
async function bootstrap() {
  onst app = await NestFactory.create(/* 創(chuàng)建app的業(yè)務(wù)邏輯*/)
  app.use(cors({
    origin:"http://localhost:8080",
    credentials:true
  }));
  await app.listen(3000)
}
bootstrap();

在上述的代碼中我們可以直接通過(guò)app.use來(lái)使用core這個(gè)express中的中間件。從而使得server端支持core跨域等。

初此之外,跟nestjs的中間件也完全保留了express中的中間件的特點(diǎn):

在中間件中接受response和request作為參數(shù),并且可以修改請(qǐng)求對(duì)象request和結(jié)果返回對(duì)象response

可以結(jié)束對(duì)于請(qǐng)求的處理,直接將請(qǐng)求的結(jié)果返回,也就是說(shuō)可以在中間件中直接res.send等。

在該中間件處理完畢后,如果沒有將請(qǐng)求結(jié)果返回,那么可以通過(guò)next方法,將中間件傳遞給下一個(gè)中間件處理。

在nestjs中,中間件跟express中完全一樣,除了可以復(fù)用express中間件外,在nestjs中針對(duì)某一個(gè)特定的路由來(lái)使用中間件也十分的方便:

class ApplicationModule implements NestModule {
  configure(consumer: MiddlewareConsumer) {
    consumer
      .apply(LoggerMiddleware)
      .forRoutes("cats");
  }
}

上面就是對(duì)于特定的路由url為/cats的時(shí)候,使用LoggerMiddleware中間件。

(2)、Exception filters異常過(guò)濾器

??Exception filters異常過(guò)濾器可以捕獲在后端接受處理任何階段所跑出的異常,捕獲到異常后,然后返回處理過(guò)的異常結(jié)果給客戶端(比如返回錯(cuò)誤碼,錯(cuò)誤提示信息等等)。

??我們可以自定義一個(gè)異常過(guò)濾器,并且在這個(gè)異常過(guò)濾器中可以指定需要捕獲哪些異常,并且對(duì)于這些異常應(yīng)該返回什么結(jié)果等,舉例一個(gè)自定義過(guò)濾器用于捕獲HttpException異常的例子。

@Catch(HttpException)
export class HttpExceptionFilter implements ExceptionFilter {
  catch(exception: HttpException, host: ArgumentsHost) {
    const ctx = host.switchToHttp();
    const response = ctx.getResponse();
    const request = ctx.getRequest();
    const status = exception.getStatus();

    response
      .status(status)
      .json({
        statusCode: status,
        timestamp: new Date().toISOString(),
        path: request.url,
      });
  }
}

??我們可以看到host是實(shí)現(xiàn)了ArgumentsHost接口的,在host中可以獲取運(yùn)行環(huán)境中的信息,如果在http請(qǐng)求中那么可以獲取request和response,如果在socket中也可以獲取client和data信息。

??同樣的,對(duì)于異常過(guò)濾器,我們可以指定在某一個(gè)模塊中使用,或者指定其在全局使用等。

(3)Pipes管道

??Pipes一般用戶驗(yàn)證請(qǐng)求中參數(shù)是否符合要求,起到一個(gè)校驗(yàn)參數(shù)的功能。

??比如我們對(duì)于一個(gè)請(qǐng)求中的某些參數(shù),需要校驗(yàn)或者轉(zhuǎn)化參數(shù)的類型:

@Injectable()
export class ParseIntPipe implements PipeTransform {
  transform(value: string, metadata: ArgumentMetadata): number {
    const val = parseInt(value, 10);
    if (isNaN(val)) {
      throw new BadRequestException("Validation failed");
    }
    return val;
  }
}

??上述的ParseIntPipe就可以把參數(shù)轉(zhuǎn)化成十進(jìn)制的整型數(shù)字。我們可以這樣使用:

@Get(":id")
async findOne(@Param("id", new ParseIntPipe()) id) {
  return await this.catsService.findOne(id);
}

??對(duì)于get請(qǐng)求中的參數(shù)id,調(diào)用new ParseIntPipe方法來(lái)將id參數(shù)轉(zhuǎn)化成十進(jìn)制的整數(shù)。

(4)Guards守衛(wèi)

??Guards守衛(wèi),其作用就是決定一個(gè)請(qǐng)求是否應(yīng)該被處理函數(shù)接受并處理,當(dāng)然我們也可以在middleware中間件中來(lái)做請(qǐng)求的接受與否的處理,與middleware相比,Guards可以獲得更加詳細(xì)的關(guān)于請(qǐng)求的執(zhí)行上下文信息。

通常Guards守衛(wèi)層,位于middleware之后,請(qǐng)求正式被處理函數(shù)處理之前。

下面是一個(gè)Guards的例子:

@Injectable()
export class AuthGuard implements CanActivate {
  canActivate(
    context: ExecutionContext,
  ): boolean | Promise | Observable {
    const request = context.switchToHttp().getRequest();
    return validateRequest(request);
  }
}

這里的context實(shí)現(xiàn)了一個(gè)ExecutionContext接口,該接口中具有豐富的執(zhí)行上下文信息。

export interface ArgumentsHost {
  getArgs = any[]>(): T;
  getArgByIndex(index: number): T;
  switchToRpc(): RpcArgumentsHost;
  switchToHttp(): HttpArgumentsHost;
  switchToWs(): WsArgumentsHost;
}

export interface ExecutionContext extends ArgumentsHost {
  getClass(): Type;
  getHandler(): Function;
}

除了ArgumentsHost中的信息外,ExecutionContext還包含了getClass用戶獲取對(duì)于某一個(gè)路由處理的,控制器。而getClass用于獲取返回對(duì)于指定路由后臺(tái)處理時(shí)的處理函數(shù)。

對(duì)于Guards處理函數(shù),如果返回true,那么請(qǐng)求會(huì)被正常的處理,如果返回false那么請(qǐng)求會(huì)拋出異常。

(5)、interceptors攔截器

?? 攔截器可以給每一個(gè)需要執(zhí)行的函數(shù)綁定,攔截器將在該函數(shù)執(zhí)行前或者執(zhí)行后運(yùn)行??梢赞D(zhuǎn)換函數(shù)執(zhí)行后返回的結(jié)果等。

概括來(lái)說(shuō):

interceptors攔截器在函數(shù)執(zhí)行前或者執(zhí)行后可以運(yùn)行,如果在執(zhí)行后運(yùn)行,可以攔截函數(shù)執(zhí)行的返回結(jié)果,修改參數(shù)等。

再來(lái)舉一個(gè)超時(shí)處理的例子:

@Injectable()
export class TimeoutInterceptor implements NestInterceptor{
  intercept(
    context:ExecutionContext,
    call$:Observable
  ):Observable{
    return call$.pipe(timeout(5000));
  }
}

該攔截器可以定義在控制器上,可以處理超時(shí)請(qǐng)求。

四、nestjs的特點(diǎn)總結(jié)

??最后總結(jié)一下nestjs的優(yōu)缺。

nestjs的優(yōu)點(diǎn):

完美的支持typescript,因此可以使用日益繁榮的ts生態(tài)工具

兼容express中間件,因?yàn)閑xpress是最早出現(xiàn)的輕量級(jí)的node server端框架,nestjs能夠利用所有express的中間件,使其生態(tài)完善

層層處理,一定程度上可以約束代碼,比如何時(shí)使用中間件、何時(shí)需要使用guards守衛(wèi)等。

依賴注入以及模塊化的思想,提供了完整的mvc的鏈路,使得代碼結(jié)構(gòu)清晰,便于維護(hù),這里的m是數(shù)據(jù)層可以通過(guò)modules的形式注入,比如通過(guò)typeorm的entity就可以在模塊中注入modules。

完美支持rxjs

文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/101663.html

相關(guān)文章

  • ExpressNestjs,談?wù)?/em>Nestjs設(shè)計(jì)思想使用方法

    摘要:三的洋蔥模型這里簡(jiǎn)單講講在中是如何分層的,也就是說(shuō)請(qǐng)求到達(dá)服務(wù)端后如何層層處理,直到響應(yīng)請(qǐng)求并將結(jié)果返回客戶端。從而使得端支持跨域等。 ??最近已經(jīng)使用過(guò)一段時(shí)間的nestjs,讓人寫著有一種java spring的感覺,nestjs可以使用express的所有中間件,此外完美的支持typescript,與數(shù)據(jù)庫(kù)關(guān)系映射typeorm配合使用可以快速的編寫一個(gè)接口網(wǎng)關(guān)。本文會(huì)介紹一下作...

    wawor4827 評(píng)論0 收藏0
  • 以Referer方案寫一個(gè)圖片防盜鏈服務(wù)并實(shí)現(xiàn)網(wǎng)頁(yè)端"破解"

    摘要:在同等安全級(jí)別的情況下,發(fā)送文件的源作為引用地址,但是在降級(jí)的情況下不會(huì)發(fā)送。 什么是盜鏈 資源不在自己服務(wù)器上, 而通過(guò)技術(shù)手段, 把資源放置到自己的網(wǎng)站中, 通過(guò)這種方法盜取他人的資源. 什么是Referer Referer是http請(qǐng)求header的一部分, 當(dāng)瀏覽器(或者模擬瀏覽器行為)向web服務(wù)器發(fā)送請(qǐng)求的時(shí)候,頭信息里有包含 Referer. 它表示當(dāng)前接口的訪問(wèn)來(lái)源...

    sPeng 評(píng)論0 收藏0
  • 聊聊Typescript中設(shè)計(jì)模式——裝飾器篇(decorators)

    摘要:本文從裝飾模式出發(fā),聊聊中的裝飾器和注解。該函數(shù)的函數(shù)名。不提供元數(shù)據(jù)的支持。中的元數(shù)據(jù)操作可以通過(guò)包來(lái)實(shí)現(xiàn)對(duì)于元數(shù)據(jù)的操作。 ??隨著Typescript的普及,在KOA2和nestjs等nodejs框架中經(jīng)??吹筋愃朴趈ava spring中注解的寫法。本文從裝飾模式出發(fā),聊聊Typescipt中的裝飾器和注解。 什么是裝飾者模式 Typescript中的裝飾器 Typescr...

    yiliang 評(píng)論0 收藏0
  • Nest.js 入門小例子

    摘要:例子目錄結(jié)構(gòu)如下代碼編寫工具采用目錄功能具體描述項(xiàng)目根目錄模塊安裝目錄。此例子對(duì)的版本和以上的版本也是有要求的,具體看官方文檔。有中文文檔的,但是那個(gè)網(wǎng)站有時(shí)候會(huì)訪問(wèn)不了。不過(guò)在上有中文翻譯的托管。此例子完整代碼在上也可以查看。 Nest.js 入門小例子 前言:雖然使用官網(wǎng)的cli工具生成了一個(gè)基本的項(xiàng)目,但是由于正常開發(fā)中的項(xiàng)目的目錄結(jié)構(gòu)往往需要自定義的,官方這個(gè)例子并不能滿足我們...

    olle 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

chanjarster

|高級(jí)講師

TA的文章

閱讀更多
最新活動(dòng)
閱讀需要支付1元查看
<