深入講解NestJS中的守衛、攔截器和過濾器

NestJS提供了許多強大的工具和功能來管理和處理請求。在本文中,我們將深入探討 NestJS 中的守衛(Guards)、攔截器(Interceptors)和過濾器(Filters),並通過實際應用中的實例說明它們的使用場景。同時,我們還將通過案例說明它們與中間件的區別。

守衛(Guards)

守衛的概念

守衛是一種用於控制請求流的機制,可以在請求到達處理器之前進行驗證和檢查。它們通常用於實現認證和授權邏輯。

創建守衛

要創建一個守衛,需要實現 CanActivate 接口,並定義 canActivate 方法。以下是一個簡單的認證守衛示例:

1
import { Injectable, CanActivate, ExecutionContext } from "@nestjs/common";
2
import { Observable } from "rxjs";
3
4
@Injectable()
5
export class AuthGuard implements CanActivate {
6
canActivate(
7
context: ExecutionContext,
8
): boolean | Promise<boolean> | Observable<boolean> {
9
const request = context.switchToHttp().getRequest();
10
return this.validateRequest(request);
11
}
12
13
validateRequest(request: any): boolean {
14
// 驗證邏輯
15
return request.headers.authorization === "my-secret-token"; // 簡單的示例
16
}
17
}

應用守衛

守衛可以在控制器或方法級別應用,使用 @UseGuards 裝飾器:

控制器級別
1
import { Controller, Get, UseGuards } from "@nestjs/common";
2
import { AuthGuard } from "./auth.guard";
3
4
@Controller("cats")
5
@UseGuards(AuthGuard)
6
export class CatsController {
7
@Get()
8
findAll() {
9
return "This action returns all cats";
10
}
11
}
方法級別
1
import { Controller, Get, UseGuards } from "@nestjs/common";
2
import { AuthGuard } from "./auth.guard";
3
4
@Controller("cats")
5
export class CatsController {
6
@Get()
7
@UseGuards(AuthGuard)
8
findAll() {
9
return "This action returns all cats";
10
}
11
}
全局級別
1
import { NestFactory } from "@nestjs/core";
2
import { AppModule } from "./app.module";
3
import { AuthGuard } from "./auth.guard";
4
5
async function bootstrap() {
6
const app = await NestFactory.create(AppModule);
7
app.useGlobalGuards(new AuthGuard());
8
await app.listen(3000);
9
}
10
bootstrap();

守衛的實際應用場景

守衛常用於保護需要認證或授權的路由。例如,在一個需要用戶登錄才能訪問的路由中,可以使用守衛來驗證用戶身份。

攔截器(Interceptors)

攔截器的概念

攔截器是一種可以在處理請求之前和之後執行自定義邏輯的機制。它們常用於日誌記錄、變換響應數據和異常處理等。

創建攔截器

要創建一個攔截器,需要實現 NestInterceptor 接口,並定義 intercept 方法。以下是一個響應數據格式化的攔截器示例:

1
import {
2
Injectable,
3
NestInterceptor,
4
ExecutionContext,
5
CallHandler,
6
} from "@nestjs/common";
7
import { Observable } from "rxjs";
8
import { map } from "rxjs/operators";
9
10
@Injectable()
11
export class TransformInterceptor implements NestInterceptor {
12
intercept(context: ExecutionContext, next: CallHandler): Observable<any> {
13
return next.handle().pipe(map((data) => ({ data })));
14
}
15
}

應用攔截器

攔截器可以在控制器或方法級別應用,使用 @UseInterceptors 裝飾器:

控制器級別
1
import { Controller, Get, UseInterceptors } from "@nestjs/common";
2
import { TransformInterceptor } from "./transform.interceptor";
3
4
@Controller("cats")
5
@UseInterceptors(TransformInterceptor)
6
export class CatsController {
7
@Get()
8
findAll() {
9
return [{ name: "Tom" }, { name: "Jerry" }];
10
}
11
}
方法級別
1
import { Controller, Get, UseInterceptors } from "@nestjs/common";
2
import { TransformInterceptor } from "./transform.interceptor";
3
4
@Controller("cats")
5
export class CatsController {
6
@Get()
7
@UseInterceptors(TransformInterceptor)
8
findAll() {
9
return [{ name: "Tom" }, { name: "Jerry" }];
10
}
11
}
全局級別
1
import { NestFactory } from "@nestjs/core";
2
import { AppModule } from "./app.module";
3
import { TransformInterceptor } from "./transform.interceptor";
4
5
async function bootstrap() {
6
const app = await NestFactory.create(AppModule);
7
app.useGlobalInterceptors(new TransformInterceptor());
8
await app.listen(3000);
9
}
10
bootstrap();

攔截器的實際應用場景

攔截器常用於日誌記錄、響應數據轉換和異常處理。例如,在一個需要對響應數據進行統一格式化的路由中,可以使用攔截器來變換數據。

過濾器(Filters)

過濾器的概念

過濾器是一種用於捕獲和處理未處理異常的機制。它們可以捕獲控制器中的任何未處理異常,並執行自定義的錯誤處理邏輯。

創建過濾器

要創建一個過濾器,需要實現 ExceptionFilter 接口,並定義 catch 方法。以下是一個全局異常過濾器示例:

1
import {
2
ExceptionFilter,
3
Catch,
4
ArgumentsHost,
5
HttpException,
6
} from "@nestjs/common";
7
import { Request, Response } from "express";
8
9
@Catch(HttpException)
10
export class HttpExceptionFilter implements ExceptionFilter {
11
catch(exception: HttpException, host: ArgumentsHost) {
12
const ctx = host.switchToHttp();
13
const response = ctx.getResponse<Response>();
14
const request = ctx.getRequest<Request>();
15
const status = exception.getStatus();
16
17
response.status(status).json({
18
statusCode: status,
19
timestamp: new Date().toISOString(),
20
path: request.url,
21
});
22
}
23
}

應用過濾器

過濾器可以在控制器或方法級別應用,使用 @UseFilters 裝飾器,也可以全局應用:

控制器級別
1
import { Controller, Get, UseFilters } from "@nestjs/common";
2
import { HttpExceptionFilter } from "./http-exception.filter";
3
4
@Controller("cats")
5
@UseFilters(HttpExceptionFilter)
6
export class CatsController {
7
@Get()
8
findAll() {
9
throw new HttpException("Forbidden", 403);
10
}
11
}
方法級別
1
import { Controller, Get, UseFilters } from "@nestjs/common";
2
import { HttpExceptionFilter } from "./http-exception.filter";
3
4
@Controller("cats")
5
export class CatsController {
6
@Get()
7
@UseFilters(HttpExceptionFilter)
8
findAll() {
9
throw new HttpException("Forbidden", 403);
10
}
11
}
全局級別
1
import { NestFactory } from "@nestjs/core";
2
import { AppModule } from "./app.module";
3
import { HttpExceptionFilter } from "./http-exception.filter";
4
5
async function bootstrap() {
6
const app = await NestFactory.create(AppModule);
7
app.useGlobalFilters(new HttpExceptionFilter());
8
await app.listen(3000);
9
}
10
bootstrap();

過濾器的實際應用場景

過濾器常用於全局錯誤處理。例如,可以創建一個全局異常過濾器來統一處理所有未處理的異常,並返回一致的錯誤響應。

中間件(Middleware)

中間件的概念

中間件是一種用於在請求到達路由處理器之前和響應發送到客戶端之前執行的函數。中間件可以用於處理請求、修改響應、終止請求-響應週期或調用下一個中間件函數。

創建中間件

要創建一個中間件,需要實現 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
}

應用中間件

中間件可以在模塊中應用,使用 forRoutes 方法:

1
import { Module, NestModule, MiddlewareConsumer } from "@nestjs/common";
2
import { CatsController } from "./cats.controller";
3
import { LoggerMiddleware } from "./logger.middleware";
4
5
@Module({
6
controllers: [CatsController],
7
})
8
export class CatsModule implements NestModule {
9
configure(consumer: MiddlewareConsumer) {
10
consumer.apply(LoggerMiddleware).forRoutes(CatsController);
11
}
12
}

中間件的實際應用場景

中間件常用於日誌記錄、請求驗證、響應壓縮等。例如,在一個需要對所有請求進行日誌記錄的模塊中,可以使用中間件來記錄請求信息。

守衛、攔截器、過濾器和中間件的區別

  • 守衛(Guards):用於控制請求是否可以繼續執行,常用於認證和授權。
  • 攔截器(Interceptors):用於在請求前後執行額外邏輯,常用於日誌記錄、響應數據轉換和異常處理。
  • 過濾器(Filters):用於捕獲和處理未處理異常,常用於全局錯誤處理。
  • 中間件(Middleware):用於在請求到達路由處理器之前和響應發送到客戶端之前執行額外邏輯,常用於日誌記錄、請求驗證和響應壓縮。

總結

本文深入探討了 NestJS 中的守衛、攔截器、過濾器和中間件,並通過實例說明了它們在實際應用中的使用場景。通過合理使用這些工具,我們可以構建出功能強大且靈活的 NestJS 應用。同時,我們還討論了它們之間的區別,幫助大家更好地理解這些工具的應用場景。