1.介紹 nestjs 分層元件 Filter
nestjs 會透過 Filter 元件來捕捉其他生命周期元件所拋出的 Exception,然後對這個 Exception 做妥善的處理邏輯。這個元件就是用來處理 Exception 的元件,相較於之前需要把 Exception 散在每個 handler 獨立處理。
nestjs 的概念是透過 Exception Filter 把要處理的Exception ,各自用 Filter 套在要抓取的範圍上。
nestjs 本身有一個預設全域的 HttpExcpetionFilter,會把沒處理的 Exception 做處理。但如果本身是 unresolved 的 Exception 比如說包含在 Promise 則無法透過 Filter 過濾掉。
另一個要注意的是,如同其他語言的 Exception 處理器。抓取 Exception 也向集合一樣,如果你 Filter 的類別順序是父集合然後才是子集合,那子集合那裡永遠抓取不到,因為大的類別已經把抓取完。所以,如果同時有繼承關係的 Exception 做 Filter 。順序要是子類別先,父親類別後。
import {
ArgumentsHost,
Catch,
ExceptionFilter,
HttpException,
Logger,
} from '@nestjs/common';
import { Response, Request } from 'express';
@Catch(HttpException)
export class HttpExceptionFilter implements ExceptionFilter {
private readonly logger = new Logger(HttpExceptionFilter.name);
catch(exception: HttpException, host: ArgumentsHost) {
this.logger.log(HttpExceptionFilter.name);
const ctx = host.switchToHttp();
const response = ctx.getResponse<Response>();
const request = ctx.getRequest<Request>();
const status = exception.getStatus();
response.status(status).json({
statusCode: status,
timestamp: new Date().toISOString(),
path: request.url,
});
}
}
一共有三種
以 Controller 的 handler 為擷取範圍 , 針對特定 route 做處理。如下:
@Post()
@UseFilters(HttpExceptionFilter)
async create(@Body() createCatDto: CreateCatDto) {
throw new ForbiddenException();
}
以 Controller 作為擷取範圍,針對特定的 prefix route 做處理。如下:
@UseFilters(HttpExceptionFilter)
export class PetsController {}
app 範圍或有可以稱作全局範圍,針對所有 route 做處理。如下:
async function bootstrap() {
const app = await NestFactory.create(AppModule);
app.useGlobalFilters(new HttpExceptionFilter());
await app.listen(3000);
}
bootstrap();
也可以透過 AppModule 做 Provider 注入
import { Module } from '@nestjs/common';
import { APP_FILTER } from '@nestjs/core';
@Module({
providers: [
{ provide: APP_FILTER, useClass: ExceptionsLoggerFilter}
],
})
export class AppModule {}
要特別注意的是, Filter 作用是錯誤攔截器,但有錯誤發生接著就是攔截器處理邏輯,然後就結束了,所以這段是處理流程尾段之一。
必須要想要在攔截錯誤之後,該做什麼處理,比如 logger error 紀錄,以及回應處理。
nestjs 內建的 HttpException ,主要包含兩個欄為
針對其他 protocol , nestjs 也有針對 RPC 或是 WebSocket 內建一些 Exception 。 假如內建的 Exception 不符合需求,可以基於這些 Exception 做繼承或組合延伸。
nestjs Filter 元件是用來做錯誤攔截器的功能,避免以往需要透過層層轉拋的疊床架屋方式。這樣標準化的作法,可以讓錯誤處理流程單一職責,同時也提供一個方法,讓開發者去集中管理這些邏輯。
特別要注意的是,整個 nestjs 框架的預設程式進入點是 main.ts。這個裏面運行著一個 bootstrap() 程式。
這個 bootstrap() 程式,預設沒有其他抓取錯誤的邏輯。所以如果要在,最外層處理,一些在 Exception Filter 漏掉沒抓取的錯誤,需要針對 process 的一些例外事件。比如 uncaughtException, rejectionHandled 這些事件做 listener 處理。