深入理解NestJS中間件:創建和應用中間件處理請求與響應

在 NestJS 中,中間件(Middleware)是處理請求和響應的重要組件。本文將詳細介紹 NestJS 中間件的概念,並講解如何創建和應用中間件來處理請求和響應。

什麼是中間件

在 NestJS 中,中間件是一個函數,它可以訪問請求對象(req)、響應對象(res)和應用程序請求-響應週期中的下一個中間件函數(next)。中間件可以在處理請求前進行操作,例如驗證用戶身份、記錄日誌、修改請求對象等。

中間件的定義與使用方式類似於 Express.js,但 NestJS 提供了更強大的模塊化和類型安全支持。

創建中間件

要創建一個中間件,需要實現 NestMiddleware 介面並定義 use 方法。以下是一個簡單的日誌記錄中間件示例:

1
import { Injectable, NestMiddleware } from "@nestjs/common";
2
import { Request, Response, NextFunction } from "express";
3
4
@Injectable()
5
export class LoggerMiddleware implements NestMiddleware {
6
use(req: Request, res: Response, next: NextFunction) {
7
console.log(`Request...`);
8
next();
9
}
10
}

在上面的示例中,LoggerMiddleware 中間件會記錄每個請求並調用 next() 函數將控制權交給下一個中間件或路由處理器。

應用中間件

要應用中間件,可以在模塊的 configure 方法中使用 MiddlewareConsumer 來指定中間件的應用範圍。以下是一個將 LoggerMiddleware 應用於所有路由的示例:

1
import { Module, NestModule, MiddlewareConsumer } from "@nestjs/common";
2
import { LoggerMiddleware } from "./logger.middleware";
3
4
@Module({
5
// 其他模塊配置
6
})
7
export class AppModule implements NestModule {
8
configure(consumer: MiddlewareConsumer) {
9
consumer.apply(LoggerMiddleware).forRoutes("*");
10
}
11
}

apply 方法指定要應用的中間件,forRoutes 方法指定中間件的應用範圍。forRoutes('*') 表示將中間件應用於所有路由。

中間件示例

修改請求對象

下面的中間件會添加一個自定義屬性 customProperty 到請求對象中:

1
import { Injectable, NestMiddleware } from "@nestjs/common";
2
import { Request, Response, NextFunction } from "express";
3
4
@Injectable()
5
export class CustomPropertyMiddleware implements NestMiddleware {
6
use(req: Request, res: Response, next: NextFunction) {
7
req["customProperty"] = "Custom Value";
8
next();
9
}
10
}

修改響應對象

以下是一個修改響應對象的中間件示例:

1
import { Injectable, NestMiddleware } from "@nestjs/common";
2
import { Request, Response, NextFunction } from "express";
3
4
@Injectable()
5
export class ResponseModifierMiddleware implements NestMiddleware {
6
use(req: Request, res: Response, next: NextFunction) {
7
res.on("finish", () => {
8
console.log("Response finished");
9
});
10
next();
11
}
12
}

多個中間件協作

多個中間件可以一起工作,每個中間件可以獨立執行其操作。以下是一個使用 LoggerMiddlewareCustomPropertyMiddleware 的示例:

1
import { Module, NestModule, MiddlewareConsumer } from "@nestjs/common";
2
import { LoggerMiddleware } from "./logger.middleware";
3
import { CustomPropertyMiddleware } from "./custom-property.middleware";
4
5
@Module({
6
// 其他模塊配置
7
})
8
export class AppModule implements NestModule {
9
configure(consumer: MiddlewareConsumer) {
10
consumer.apply(LoggerMiddleware, CustomPropertyMiddleware).forRoutes("*");
11
}
12
}

在上面的示例中,LoggerMiddleware 會記錄請求日誌,CustomPropertyMiddleware 會在請求對象中添加自定義屬性。所有請求都會經過這兩個中間件。

forRoutes 和 exclude 的多種用法

forRoutes 方法可以指定中間件應用於特定的路徑、控制器或方法。

應用於特定路徑

1
consumer
2
.apply(LoggerMiddleware)
3
.forRoutes({ path: "cats", method: RequestMethod.GET });

應用於特定控制器

1
import { CatsController } from "./cats.controller";
2
3
consumer.apply(LoggerMiddleware).forRoutes(CatsController);

應用於多個路徑和方法

1
consumer
2
.apply(LoggerMiddleware)
3
.forRoutes(
4
{ path: "cats", method: RequestMethod.GET },
5
{ path: "dogs", method: RequestMethod.POST },
6
);

排除特定路徑

exclude 方法用於排除特定路徑,使中間件不應用於這些路徑:

1
consumer
2
.apply(LoggerMiddleware)
3
.exclude(
4
{ path: "cats", method: RequestMethod.GET },
5
{ path: "dogs", method: RequestMethod.POST },
6
)
7
.forRoutes("*");

在上面的示例中,LoggerMiddleware 會應用於所有路徑,除了 GET /catsPOST /dogs

Functional 中間件

除了類中間件,NestJS 還支持使用函數創建中間件。以下是一個函數中間件示例:

1
import { Request, Response, NextFunction } from "express";
2
3
export function logger(req: Request, res: Response, next: NextFunction) {
4
console.log(`Request...`);
5
next();
6
}

使用函數中間件時,不需要實現 NestMiddleware 介面。可以直接在模塊中應用:

1
import { Module, NestModule, MiddlewareConsumer } from "@nestjs/common";
2
import { logger } from "./logger.middleware";
3
4
@Module({
5
// 其他模塊配置
6
})
7
export class AppModule implements NestModule {
8
configure(consumer: MiddlewareConsumer) {
9
consumer.apply(logger).forRoutes("*");
10
}
11
}

總結

本文詳細介紹了 NestJS 中間件的概念,並講解了如何創建和應用中間件來處理請求和響應。通過使用中間件,開發者可以在請求處理過程中執行各種操作,如身份驗證、日誌記錄和請求修改,從而增強應用程序的功能和安全性。我們還展示了多個中間件協作的示例,說明了如何修改請求和響應對象,以及如何使用 forRoutesexclude 方法來控制中間件的應用範圍。此外,還介紹了如何創建和應用函數中間件。