iT邦幫忙

2024 iThome 鐵人賽

DAY 9
1

nestjs 分層元件 Filter

目標

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 。順序要是子類別先,父親類別後

image

語法

  1. 需要實作 ExceptionFilter 介面
  2. 複寫 catch 方法
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,
    });
  }
}

作用範圍

一共有三種

1. handler 範圍

以 Controller 的 handler 為擷取範圍 , 針對特定 route 做處理。如下:

@Post()
@UseFilters(HttpExceptionFilter)
async create(@Body() createCatDto: CreateCatDto) {
  throw new ForbiddenException();
}

2. Controller 範圍

以 Controller 作為擷取範圍,針對特定的 prefix route 做處理。如下:

@UseFilters(HttpExceptionFilter)
export class PetsController {}

3. app 範圍

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 處理流程

要特別注意的是, Filter 作用是錯誤攔截器,但有錯誤發生接著就是攔截器處理邏輯,然後就結束了,所以這段是處理流程尾段之一。

必須要想要在攔截錯誤之後,該做什麼處理,比如 logger error 紀錄,以及回應處理。

nestjs 內建的 HttpException

nestjs 內建的 HttpException ,主要包含兩個欄為

  1. response:
    主要就是 error 的包含的資訊如 message, request 可協助查詢錯誤的資料等等
  2. status:
    Http Code 就是 http 的狀態碼

以下是常用的 HttpException

  • BadRequestException
  • UnauthorizedException
  • NotFoundException
  • ForbiddenException
  • NotAcceptableException
  • RequestTimeoutException
  • ConflictException
  • GoneException
  • HttpVersionNotSupportedException
  • PayloadTooLargeException
  • UnsupportedMediaTypeException
  • UnprocessableEntityException
  • InternalServerErrorException
  • NotImplementedException
  • ImATeapotException
  • MethodNotAllowedException
  • BadGatewayException
  • ServiceUnavailableException
  • GatewayTimeoutException
  • PreconditionFailedException

額外的 Exception

針對其他 protocol , nestjs 也有針對 RPC 或是 WebSocket 內建一些 Exception 。 假如內建的 Exception 不符合需求,可以基於這些 Exception 做繼承或組合延伸。

結論

nestjs Filter 元件是用來做錯誤攔截器的功能,避免以往需要透過層層轉拋的疊床架屋方式。這樣標準化的作法,可以讓錯誤處理流程單一職責,同時也提供一個方法,讓開發者去集中管理這些邏輯。

特別要注意的是,整個 nestjs 框架的預設程式進入點是 main.ts。這個裏面運行著一個 bootstrap() 程式。

這個 bootstrap() 程式,預設沒有其他抓取錯誤的邏輯。所以如果要在,最外層處理,一些在 Exception Filter 漏掉沒抓取的錯誤,需要針對 process 的一些例外事件。比如 uncaughtException, rejectionHandled 這些事件做 listener 處理。


上一篇
nestjs 分層元件 Pipe 與 Serialization
下一篇
nestjs 分層架構 Interceptor
系列文
透過 nestjs 框架,讓 nodejs 系統維護度增加31
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

1 則留言

0
孤獨一隻雞
iT邦研究生 4 級 ‧ 2024-09-09 18:36:53

少抽點菸

我要留言

立即登入留言