什麼是 Middleware
? Middleware
是介於 Client 端與後端路由中間的一層或是多層 Function,而該 Functions 能存取 Request
與 Request
資訊,也可以透過 next()
來控制流程。
NestJS
裡的 Middleware
基本概念與 express
的 Middleware
相同,所以相關的資訊也可以參考 express middleware。而以下的幾件事情是可以透過 Middleware
完成的
- 執行任何程式碼
- 改變 Request / Response 物件內容
- 結束 Request /Response 生命週期
- 執行下一個 Middleware ,表示可以串接多個 Middleware
建立
可以透過 CLI 的指令建立 Middleware
1 | nest g mi <middleware-name> |
當建立完成後,以下為基本的 middleware 程式碼架構
1 | import { Injectable, NestMiddleware } from '@nestjs/common'; |
設定
當建立完一個 middleware 後,當然需要告訴 NestJS
說,這一個 Middleware
需要套用在那些路由規則上,這裡就先設定在最上層的 AppModule
內
-
實作
NestModule
介面 -
建立
configure
方法1
2
3
4
5
6
7
8
9
10
11
12import { Module, NestModule, MiddlewareConsumer } from '@nestjs/common';
import { AppService } from './app.service';
import { ProductsController } from './products/products.controller';
({
imports: [],
controllers: [ProductsController],
providers: [AppService],
})
export class AppModule implements NestModule {
configure(consumer: MiddlewareConsumer) {}
} -
利用 consumer 來設定 middleware 適用的路由範圍
1
2
3
4
5export class AppModule implements NestModule {
configure(consumer: MiddlewareConsumer) {
consumer.apply(CheckMiddleware).forRoutes(ProductsController);
}
}- apply 可以放多個 middleware,且會依序執行,但前提是每一個 middleware 都有執行
next()
- 可以設定排除規則,
exclude( { path: 'products', method: RequestMethod.POST })
,但根據官網說明,此規則並不適用於 functional middleware,在下面會介紹什麼是 functional middleware forRoutes
有以下的設定方式- 直接放 Controller Class
- 指定路由
forRoutes('products')
- 指定路由與請求方式
forRoutes({path: 'products', method: RequestMethod.GET })
- 也支援 Route wildcards 的方式,
forRoutes({ path: 'ab*cd', method: RequestMethod.ALL });
- apply 可以放多個 middleware,且會依序執行,但前提是每一個 middleware 都有執行
-
如果要設定成全域使用的 middleware 時,可以在
main.ts
內設定1
2
3const app = await NestFactory.create(AppModule);
app.use(CheckMiddleware);
await app.listen(3000);
Middleware 進一步說明
那到底 Middleware
可以做到怎樣的事情呢? 這裡有一個簡單的範例
攔截所有的 Request ,不給進 ProductController
- middleware 的設定如上,直接套用
ProductController
1 | import { Injectable, NestMiddleware, HttpStatus } from '@nestjs/common'; |
接下來用 Postman 來打 /products
,看結果是什麼
當然可以加上一些條件,例如 Request 的內容中,如果 queryParams
的 name 是 Kevin 時,就會直接回傳,不然就進入 ProductController
內處理
1 | import { Injectable, NestMiddleware, HttpStatus } from '@nestjs/common'; |
Functional Middleware
如果 Middleware
不需要任何使用到其他的服務,就沒有寫成 Class 的必要性,可以單純的使用 Function 來完成
1 | export function logger(req, res, next) { |