<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          五分鐘帶你入門基于Nodejs的強大的Web框架— NestJS

          共 7587字,需瀏覽 16分鐘

           ·

          2021-11-22 21:38

          點擊上方?前端Q,關(guān)注公眾號

          回復(fù)加群,加入前端Q技術(shù)交流群

          簡介

          Nest 是一個用于構(gòu)建高效,可擴展的 Node.js 服務(wù)器端應(yīng)用程序的框架。在底層,Nest 使用強大的 HTTP Server 框架,如 Express(默認)和 Fastify。Nest 在這些框架之上提供了一定程度的抽象,同時也將其 API 直接暴露給開發(fā)人員。這樣可以輕松使用每個平臺的無數(shù)第三方模塊。

          支持 TypeScript(也支持純 js 編寫代碼),默認支持最新的 ES6 等語法和特性(用 babel 做代碼轉(zhuǎn)換)。node 版本要求 >= 10.13.0, v13 版本除外。

          要了解 Nest ,建議先了解一下裝飾器,因為 Nest 里面的方法很多都是以裝飾器的方式提供的,下面我簡單介紹一下。已經(jīng)了解的朋友可以跳過~

          裝飾器

          裝飾器(Decorator)是一種與類(class)相關(guān)的語法,用來注釋或修改類和類方法。它是一種函數(shù),寫成@ + 函數(shù)名的形式。它可以放在類和類方法的定義前面。

          ??@testable
          ??class?MyTestableClass?{
          ????//?...
          ??}
          ??function?testable(target)?{
          ????target.isTestable?=?true;
          ??}
          ??MyTestableClass.isTestable?//?true

          基本上,裝飾器的行為就是下面這樣。

          ??@decorator
          ??class?A?{}
          ??//?等同于
          ??class?A?{}
          ??A?=?decorator(A)?||?A;

          也就是說,裝飾器是一個對類進行處理的函數(shù)。裝飾器函數(shù)的第一個參數(shù),就是所要裝飾的目標(biāo)類。

          注意點

          • 裝飾器對類的行為的改變,是代碼編譯時發(fā)生的,而不是在運行時。這意味著,裝飾器能在編譯階段運行代碼。也就是說,裝飾器本質(zhì)就是編譯時執(zhí)行的函數(shù)。
          • 裝飾器只能用于類和類的方法,不能用于函數(shù),因為存在函數(shù)提升。如果一定要裝飾函數(shù),可以采用高階函數(shù)的形式直接執(zhí)行。

          Nest 基本介紹

          安裝使用這里就不說了,可以到官網(wǎng)按照其引導(dǎo)來進行:https://docs.nestjs.com/first-steps。

          生成的核心文件結(jié)構(gòu)為:

          src
          ??|-app.controller.spec.ts
          ??|-app.controller.ts
          ??|-app.module.ts
          ??|-app.service.ts
          ??|-main.ts

          其代表的含義分別為:

          文件含義
          app.controller.spec.ts控制器的單元測試
          app.controller.ts控制器邏輯文件,通常含多個路由
          app.module.ts應(yīng)用程序的根模塊
          app.service.ts服務(wù)文件
          main.ts應(yīng)用程序的入口文件,它是基于NestFactory創(chuàng)建的一個Nest應(yīng)用程序?qū)嵗?/td>

          Controller

          什么是 Controller?語義化翻譯就是 控制器,它負責(zé)處理傳入的請求并將響應(yīng)結(jié)果返回給客戶端。

          Nest 中,控制器和路由機制是結(jié)合在一起的,控制器的目的是接收應(yīng)用程序的特定請求。其路由機制控制哪個控制器接收哪些請求。通常,每個控制器都有多個路由,不同的路由可以執(zhí)行不同的操作。

          我們通過裝飾器 @Controller() 來將一個類定義為控制器,如:

          import?{?Controller?}?from?'@nestjs/common';

          @Controller('test')
          export?class?TestController?{?}

          Nest 把各個HTTP的請求方法都封裝成了裝飾器,如@Get()、@Post()、@Put()、@Patch()、@Delete()、@Options()等,因此我們在實際開發(fā)中,可以直接用來裝飾對應(yīng)的請求,比如以下幾種路由:

          import?{?Controller,?Get,?Post,?Body,?Put,?Param,?Delete?}?from?'@nestjs/common';

          @Controller('test')
          export?class?TestController?{
          ??@Post()
          ??async?create(@Body()?createTestDto:?CreateTestDto)?{
          ????return?'This?action?adds?a?new?test';
          ??}

          ??@Delete(':id')
          ??async?remove(@Param('id')?id)?{
          ????return?`This?action?removes?a?#${id}?test`;
          ??}

          ??@Put(':id')
          ??async?update(@Param('id')?id,?@Body()?updateTestDto:?UpdateTestDto)?{
          ????return?`This?action?updates?a?#${id}?test`;
          ??}

          ??@Get(':id')
          ??async?findOne(@Param('id')?id)?{
          ????return?`This?action?returns?a?#${id}?test`;
          ??}
          }

          Provider

          什么是 Provider?語義化翻譯就是 提供者,在 Nest 中,除了控制器以外,幾乎所有的東西都可以被視為提供者,比如service、repository、factory、helper等等。他們都可以通過構(gòu)造函數(shù)注入依賴關(guān)系,也就是說,他們之間可以創(chuàng)建各種關(guān)系。而提供者只不過是一個用 @Injectable() 裝飾器的簡單類。

          在類聲明上,定義 @Injectable() 裝飾器,即可將該類定義為提供者。如:

          import?{?Injectable?}?from?'@nestjs/common';
          @Injectable()
          export?class?TestService?{
          ??private?readonly?test:?Test[]?=?[];

          ??async?create(createTestDto:?CreateTestDto)?{
          ????this.test.push(createTestDto);
          ??}

          ??async?remove(id:?number)?{
          ????this.test.splice(test.indexOf(test.find(t?=>?t.id?===?id)),?1);
          ??}

          ??async?update(id:?number,?updateTestDto:?UpdateTestDto)?{
          ??????if(updateTestDto.name)?this.test.find(t?=>?t.id?===?id).name?=?updateTestDto.name;
          ??}

          ??async?findOne(id:?number):?Test?{
          ??????return?this.test.find(t?=>?t.id?===?id);
          ??}
          }

          Module

          Module也是一個裝飾器,Nest 使用 Module來組織應(yīng)用程序結(jié)構(gòu),每個應(yīng)用程序至少有一個模塊,即根模塊。根模塊是 Nest 開始排列應(yīng)用程序樹的地方。當(dāng)應(yīng)用程序很小時,根模塊可能是應(yīng)用程序中唯一的模塊。不過,大多數(shù)情況下,都有很多模塊,每個模塊都有一組與其密切相關(guān)的功能。

          模塊,是用來組織 ControllerProvider,為他們在 同模塊范圍內(nèi) 建立依賴關(guān)系的。比如上面的 ControllerProvider,我們建立關(guān)系:

          import?{?Module?}?from?'@nestjs/common';
          import?{?TestController?}?from?'./test.controller';
          import?{?TestService?}?from?'./test.service';

          @Module({
          ??controllers:?[TestController],
          ??providers:?[TestService],
          })
          export?class?TestModule?{}

          只有這樣,Nest 才可以在 TestController 中通過其構(gòu)造函數(shù),依賴注入 TestService,才可以在 controller 中調(diào)用 service 服務(wù)。

          而當(dāng)不同模塊之間的服務(wù)需要互相調(diào)用時,我們就要在對應(yīng)的模塊之間導(dǎo)出和導(dǎo)入了,例如:

          import?{?Module?}?from?'@nestjs/common';
          import?{?TestController?}?from?'./test.controller';
          import?{?TestService?}?from?'./test.service';

          @Module({
          ??imports:?[],
          ??controllers:?[TestController],
          ??providers:?[TestService],
          ??exports:?[TestService]
          })
          export?class?TestModule?{}

          全局模塊

          如果你必須在很多地方都導(dǎo)入相同的模塊,這會出現(xiàn)大量的冗余。但是 Nest 將提供者封裝在模塊范圍內(nèi),如果不導(dǎo)入模塊,就無法在其他地方使用他們導(dǎo)出的提供者。但是有時候,你可能只是想提供一組隨時可用的提供者,例如:helpers、database connection 等等。針對這種特殊情況,Nest 提供了一個很強大的功能 —— 全局模塊,全局模塊一旦被導(dǎo)入到根模塊,在其他所有模塊中即可輕松的使用這個全局模塊導(dǎo)出的提供者,而且也不用在其他模塊導(dǎo)入這個全局模塊。

          將一個模塊定義為全局模塊,只需要在類上額外增加一個裝飾器 @Global() 即可,示例:

          import?{?Module,?Global?}?from?'@nestjs/common';

          @Global()
          @Module({
          ??imports:?[],
          ??controllers:?[],
          ??providers:?[],
          ??exports:?[]
          })
          export?class?TestModule?{}

          動態(tài)模塊

          Nest 模塊系統(tǒng)有一個稱為動態(tài)模塊的特性。它能夠讓我們創(chuàng)建可定制的模塊,當(dāng)導(dǎo)入模塊并向其傳入某些選項參數(shù),這個模塊根據(jù)這些選項參數(shù)來動態(tài)的創(chuàng)建不同特性的模塊,這種通過導(dǎo)入時傳入?yún)?shù)并動態(tài)創(chuàng)建模塊的特性稱為 動態(tài)模塊。

          @Module({})
          export?class?AppModule?{
          ??static?register(CustomController):?DynamicModule?{
          ????return?{
          ??????module:?AppModule,
          ??????controllers:?[CustomController],
          ??????providers:?[],
          ??????exports:?[],
          ????};
          ??}
          }

          NestFactory

          在 Nest 中,我們通過在 main 入口中調(diào)用 NestFactory.create 來創(chuàng)建 Nest 應(yīng)用實例,Nest 創(chuàng)建的實例默認是 express 實例。main 入口示例:

          import?{?NestFactory?}?from?"@nestjs/core";
          import?{?AppModule?}?from?"./app.module";

          async?function?bootstrap()?{
          ??//?使用?NestFactory?創(chuàng)建一個根模塊為?AppModule?的?Nest?app
          ??const?app?=?await?NestFactory.create(AppModule);
          ??//?將這個 Nest app 監(jiān)聽本地的 3000?端口,即:http://localhost:3000
          ??await?app.listen(3000);
          }
          bootstrap();

          Middleware

          Middleware 即中間件,它是請求發(fā)出者和路由處理器之間的橋梁,可以透明的、輕松的訪問請求和響應(yīng)對象。在 Nest 中,中間件可以有多個,他們之間使用 next() 方法作為連接,連接后的所有中間件將在整個請求-響應(yīng)周期內(nèi)通過 next()依次執(zhí)行。

          注:默認情況下,Nest 中間件等同于 Express 中間件。Nest 中間件可以是一個函數(shù),也可以是一個帶有 @Injectable() 裝飾器的類,且該類應(yīng)該實現(xiàn) NestMiddleware 接口,而函數(shù)沒有任何特殊要求。如下簡單示例:

          //?帶有?`@Injectable()`?裝飾器的類中間件
          import?{?Injectable,?NestMiddleware?}?from?'@nestjs/common';

          @Injectable()
          export?class?OAAuthMiddleware?implements?NestMiddleware?{
          ??use(req:?Request,?res:?Response,?next:?NextFunction)?{
          ????console.log('Request...:?',?req);
          ????next();
          ??}
          }
          //?函數(shù)中間件
          export?function?OAAuthMiddleware(req,?res,?next)?{
          ??console.log('res:?',?res);
          ??next();
          }

          ProviderController一樣,中間件也能夠通過構(gòu)造函數(shù)注入屬于同一模塊的依賴項。

          全局中間件使用

          為了將中間件一次性綁定到每個注冊的路由,我們可以通過 Nest 實例中的 use() 方法使用:

          const?app?=?await?NestFactory.create(ApplicationModule);
          //?這里必須使用函數(shù)中間件
          app.use(OAAuthMiddleware);
          await?app.listen(3000);

          模塊中使用

          既然中間件是請求發(fā)出者和路由處理器之間的橋梁,那么他就應(yīng)該在一個模塊的入口,即 XXXModule 類中被使用。在 Nest 中,我們只需要在模塊類中實現(xiàn) NestModule 接口:

          import?{?Module,?NestModule,?MiddlewareConsumer?}?from?'@nestjs/common';
          import?{?OAAuthMiddleware?}?from?'./common/middlewares/oAAuthMiddleware.middleware';
          import?{?TestModule?}?from?'./test/test.module';

          @Module({
          ??imports:?[TestModule],
          })
          export?class?ApplicationModule?implements?NestModule?{
          ??configure(consumer:?MiddlewareConsumer)?{
          ????consumer
          ??????.apply(OAAuthMiddleware)
          ??????.forRoutes('test');
          ??}
          }

          在上面的例子中,我們?yōu)?/test 路由處理器 (@TestController('/test')) 設(shè)置了鑒權(quán)中間件。如果只需要給 /test 路由中的某幾個請求方法設(shè)置這個中間件,那只需要改變一下 forRoutes() 方法中的參數(shù)即可:forRoutes({ path: 'test', method: RequestMethod.GET }),此時,只有 GET 請求才會被中間件攔截。如果存在很多路由規(guī)則,也可以使用通配符來處理。如:

          forRoutes({?path:?'ab*cd',?method:?RequestMethod.ALL?})

          而當(dāng)你想排除一個控制器類中的某些路由不使用中間件時,使用 exclude() 方法即可,如:

          import?{?Module,?NestModule,?MiddlewareConsumer?}?from?'@nestjs/common';
          import?{?OAAuthMiddleware?}?from?'./common/middlewares/oAAuthMiddleware.middleware';
          import?{?TestModule?}?from?'./test/test.module';

          @Module({
          ??imports:?[TestModule],
          })
          export?class?ApplicationModule?implements?NestModule?{
          ??configure(consumer:?MiddlewareConsumer)?{
          ????consumer
          ??????.apply(OAAuthMiddleware)
          ??????.exclude(
          ????????{?path:?'test',?method:?RequestMethod.GET?},
          ??????)
          ??????.forRoutes('test');
          ??}
          }

          最后

          了解了 Nest 的基本概念之后,可以安裝@nestjs/cli來體驗一下 Nest 項目,這里給大家出個思考題,如何把 Nest 項目抽離為 runtime(Nest框架) + faas(入口文件) 的形式呢?

          參考資料

          • https://www.bookstack.cn/read/es6-3rd/docs-decorator.md
          • https://docs.nestjs.com
          • http://ourjs.com/wiki/view/nestjs/02.controller



          往期推薦


          基于WebAssembly的圖片渲染/視頻處理/云原生的場景應(yīng)用有哪些?
          2021 TWeb 騰訊前端技術(shù)大會精彩回顧(附PPT)
          用oclif,碼得更快了,30秒創(chuàng)建腳手架


          最后


          • 歡迎加我微信,拉你進技術(shù)群,長期交流學(xué)習(xí)...

          • 歡迎關(guān)注「前端Q」,認真學(xué)前端,做個專業(yè)的技術(shù)人...

          點個在看支持我吧
          瀏覽 50
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          評論
          圖片
          表情
          推薦
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  波多野结衣一品二品免费观看AV | 欧美怡红院 | 成人AV导航 | 亚洲中文日韩在线观看 | 国产免费永久网站 |