[元件] Middleware

功能同 Express 的 middleware,可以存取請求物件、回應物件,並透過 next 繼續運行流程。
本篇主要介紹 class middleware(functional middleware 同 Express 就不多介紹)。
class middleware
use 是元件實際會執行的內容。
CLI 產生的初始架構中 req 與 res 是 any,要自行替換成專案目前使用的底層 HTTP 框架(Express 或 Fastify)的型別:
import { Injectable, NestMiddleware } from '@nestjs/common';import { Request, Response, NextFunction } from 'express';
@Injectable()export class TestLoggerMiddleware implements NestMiddleware { use(req: Request, res: Response, next: NextFunction) { const method = req.method; const resource = req.originalUrl;
console.log(`這是 ${method} ${resource} 觸發的 TestLoggerMiddleware`);
next(); }}部分套用
middleware 需要在 module 元件中設定好哪些路由的請求會觸發。
在 forRoutes 填入要匹配的路由:
@Module({ imports: [TestModule], controllers: [AppController, TestController], providers: [AppService],})export class AppModule implements NestModule { configure(consumer: MiddlewareConsumer) { consumer.apply(TestLoggerMiddleware).forRoutes('/test'); }}資訊
根據 middleware 的功能來決定要在哪個 module 底下套用即可。全域性質的功能通常都統整在根模組。
也可以直接指定某個 controller 下面的所有路由:
consumer.apply(TestLoggerMiddleware).forRoutes(TestController);可以傳入多個 middleware,會依照順序執行:
consumer.apply(TestLoggerMiddleware, SayHelloMiddleware).forRoutes('/test');全域套用
forRoutes 傳入 '*' 匹配全部的路由,讓所有請求都執行:
consumer.apply(TestLoggerMiddleware).forRoutes('*');或是在啟動程序中透過 app.use 傳入 middleware,但這個做法僅限 functional middleware:
async function bootstrap() { const app = await NestFactory.create(AppModule); app.use(TestLoggerMiddleware); await app.listen(process.env.PORT ?? 3000);}限制路由
forRoutes 可以設定更嚴格的匹配規則,例如請求必須是 GET 方法才執行:
consumer.apply(TestLoggerMiddleware).forRoutes( { path: '/test', method: RequestMethod.GET, }, { path: '/qq', method: RequestMethod.GET, },);也可以串上 exclude 排除特定路由:
consumer .apply(TestLoggerMiddleware) .exclude({ path: '/qq', method: RequestMethod.GET, }) .forRoutes('/test');小結
middleware 僅能存取基本的請求、回應物件,適合處理與業務邏輯無關的底層需求:
- 日誌記錄 (Logging): 記錄所有進入伺服器的 HTTP 請求基本資訊
- 請求預處理: 例如解析 Cookie、處理特定的 Header 或執行
body-parser - 跨域處理 (CORS): 設定請求來源許可