iT邦幫忙

2023 iThome 鐵人賽

DAY 5
0
自我挑戰組

初探後端世界-使用Node.js框架開發網頁系列 第 5

你需要知道的9個元件功能介紹 -4(Middleware)

  • 分享至 

  • xImage
  •  

Middleware

Middleware 是client端和controller之間的橋樑.它可以攔截存取request和respond.Middleware可以有多個,彼此之間透過next()連結.Middleware可以用於許多任務,包括:

  1. 驗證:檢查request使否有效,並拒絕無效請求
  2. 紀錄:可存取request、respond物件
  3. 改變request和respond對象
  4. 結束request-respond cycle,如果沒有結束,就用next()把控制權傳給下一個middleware
  5. 執行任何程式

Class Middleware

Class Middleware是NestJS預設情況下使用的種類,建立方式如下:

$nest g middleware <MIDDLEWARE_NAME>

產生的框架如下:

import { Injectable, NestMiddleware } from '@nestjs/common';

@Injectable()
export class LoggerMiddleware implements NestMiddleware {
  use(req: any, res: any, next: ()=>void {
    console.log('Request...');
    next();
  }
}

解釋說明:

  1. 是帶有@Injectable裝飾器的class
  2. 使用implements來實現NestMiddleware接口
  3. 使用use()方法,並透過三個參數(req、res、next)來獲得請求物件
  4. req、res的預設型別都是any,要根據自己選擇的底層(Express、Fastify)來做調整、next後接nextFunction
  5. 最後加上next()來結束這個Middleware到下一個流程.

如果預設底層是Express的話:

import { Injectable, NestMiddleware } from '@nestjs/common';
import { Request, Response, NextFunction } from 'express';

@Injectable()
export class LoggerMiddleware implements NestMiddleware {
  use(req: Request, res: Response, next: NextFunction) {
    console.log('Request...');
    next();
  }
}

使用Middleware

import { Module, NestModule, MiddlewareConsumer } from '@nestjs/common';
import { LoggerMiddleware } from './common/middleware/logger.middleware';
import { CatsModule } from './cats/cats.module';

@Module({
  imports: [CatsModule],
})
export class AppModule implements NestModule {
  configure(consumer: MiddlewareConsumer) {
    consumer
      .apply(LoggerMiddleware)
      .forRoutes('cats');
  }
}

解釋說明:
1.使用implements讓AppModule去實作NestModule
2.使用configure()方法,裡面的參數型別是MiddlewareConsumer
3.透過
consumer
的**apply()方法,去註冊我們自己設計的LoggerMiddleware
4.再透過
forRoutes()**方法,去指定哪個路由有效,這個範例,只要前綴為cats的都會有效
5.補充第4點,或是可以在forRoutes中改成CatsController(上方記得import),這樣就能針對整個Controller底下的Handler做套用了

*關於configure():https://expressjs.com/2x/guide.html#app.configure()

多個(Multiple)Middleware

使用逗號隔開不同的Middleware,要特別注意順序會有影響,先寫的Middleware會先執行

修改範例如下:
consumer.apply(CheckerMiddleware,LoggerMiddleware).forRoutes(CatsController);

此時就會先執行CheckerMiddleware再執行LoggerMiddleware.

套用指定路由(Route wildcards)

如果想針對多個不同路由或是某個特定的api去做套用.那就可以在forRoutes()中做指定,在forRoutes中設置兩個物件格式分別是path和method,path代表路由前綴,method代表需要符合的http code.而當兩個都符合條件時,才會被套用.

修改範例如下:
forRoutes({ path: 'ab*cd', method: RequestMethod.Get }, { path: '/', method: RequestMethod.Get }, );

解釋說明:
只有前綴為ab開頭cd結尾,並且符合get方法的api以及沒有前綴且符合get方法的api才會套用api

排除路由(Excluding routes)

和套用指定路由正好相反,只需要透過consumer底下的**exclude()**方法來針對符合條件的api做排除.
配置條件方法和指定路由條件一樣,設置物件格式分別為path和method

修改範例如下:

consumer
  .apply(LoggerMiddleware)
  .exclude(
    { path: 'cats', method: RequestMethod.GET },
    { path: 'cats', method: RequestMethod.POST },
  )
  .forRoutes(CatsController);

解釋說明:
我們排除掉cats路由中使用get和post方法的api,並套用在CatsController上.

全域Middleware(Global Middleware)

如果想將Middleware套用在每一個路由上的話,有兩種方法:

1. Functional Middlware中

直接在main.ts中使用app.use()
範例如下:

const app = await NestFactory.create(AppModule);
app.use(logger);
await app.listen(3000);

2. Class Middleware中

在app.module.ts實作NestModule的介面中,forRoutes()的指定路由為*即可
範例如下:

export class AppModule implements NestModule {
  configure(consumer: MiddlewareConsumer) {
    consumer
      .apply(LoggerMiddleware)
      .forRoutes('*');
  }

上一篇
你需要知道的9個元件功能介紹 -3(Modules)
下一篇
你需要知道的9個元件功能介紹 -5(Exception & Exception filter)
系列文
初探後端世界-使用Node.js框架開發網頁12
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言