NestJs Filter

26403 ワード

NestJs filter (with Java)


サンプルコードはgithub中:)

Goal


  • 了解NestJsのフィルター.

  • 実施CustomException後、該当ExceptionCatchfilter河を作成する.
  • フィルターとは?

    NestJsアプリケーション全体の未処理のすべての例外を処理するための例外層が内蔵されている.
    アプリケーション・コードで処理されていない例外は、例外レイヤで例外をキャプチャし、適切なユーザー・フレンドリーな応答を自動的に送信します.

    デフォルトでは、この操作は内蔵のグローバル例外フィルタによって実行されます.この例外処理はHttpExceptionタイプの例外です.
    例外がunrecognized(継承ではないHttpExceptionまたはHttpExceptionのクラス)の場合、クライアントは以下の基本JSONを受け取る.
    {
      "statusCode": 500,
      "message": "Internal server error"
    }

    Base Exception


    内蔵HttpExceptionclassは@nestjs/commonより提供される.
    まず、確認HttpExceptionの仕組みは以下の通りです.
    export declare class HttpException extends Error {
        private readonly response;
        private readonly status;
    
        constructor(response: string | Record<string, any>, status: number);
        initMessage(): void;
        initName(): void;
        getResponse(): string | object;
        getStatus(): number;
        static createBody(objectOrError: object | string, description?: string, statusCode?: number): object;
    }
    引き継いだError、職業はresponsestatusresponseの作用とstatusの作用は以下の通り.

  • response:クライアントに応答するJSONの本文を定義します.

  • status:HTTP通信の状態値を決定します.
  • デフォルトでは、応答クライアントのJSONには2つの基本プロパティがあります.
    {
        "statusCode": ,
        "message" : 
    }
    基本回答でmessage部分のみ変更したい場合は、HttpExceptionを生成する場合は、stringを入れるだけです.
    throw new HttpException('BadRequest', HttpStatus.BAD_REQUEST);
    
    // output
    {
        "statusCode": 400,
        "message": "BadRequest"
    }
    messageJSON全体を再定義するには、対象を入れるだけです.
    //2
    const response: Record<string, any> = {
        'status': HttpStatus.BAD_REQUEST,
        'errorMessage': 'BadRequest'
    }
    throw new HttpException(response, HttpStatus.BAD_REQUEST);
    
    // output
    {
      	// key 값이 바뀐 것을 확인할 수 있다.
        "status": 400,
        "errorMessage": "BadRequest"
    }

    Exception hierarchy


    例外階層を直接作成することが望ましい.例外階層構造の作成は、継承HttpExceptionExceptionCustom・手作りは以下の通りです.
    export class CustomHttpException extends HttpException {
      // 여기서 생성자로 미리 정의해둔 상수 혹은 객체를 받아 부모의 생성자에 넣어준다.
      constructor(response: string | Record<string, any>, status: HttpStatus) {
        super(response, status);
      }
    }
    使用以前Java作成CustomHttpExceptionの場合と大差ないことがわかる.Java中継ぎRuntimeException、編纂CustomException
    @Getter
    public class CustomHttpException extends RuntimeException{
        private final ErrorCode errorCode;
    
        public CustomHttpException(ErrorCode errorCode){
            super(errorCode.getMessage());
            this.errorCode = errorCode;
        }
    }

    Nestが提供するHttpException内蔵

    Nest共通文コードの作成の必要性を減らすため、@nestjs/common複数種類提供HttpException種類.
    種類はBuilt-in HttpExceptionで確認できます.

    Exceptionフィルタの作成


    内蔵の例外フィルタを使用すると、多くの場合を自動的に処理できますが、自動処理ではなくカスタマイズが必要です.
    この場合以前Javaで利用@RestControllerAdvice@ExceptionHandler()言語で作成Exception Handler
    @RestControllerAdvice
    public class CustomExceptionHandler {
        @ExceptionHandler(CustomHttpException.class)
        public ResponseEntity<ErrorResponse> handleCustomException(CustomHttpException e) {
            //...
        }
    }
    NestJsJavaExceptionHandler等で指定されたexceptionが発生した場合、Exceptionを定義して、当該Exception Filterへの応答をカスタマイズすることができる.Exception Filterを作成するには、ExceptionFilterインタフェースを実現し、catch()内で当該Exceptionへの応答を処理する.
    // ExceptionFilter interface
    // 제네릭을 통해 `Exception`의 타입을 지정해 줄 수 있다.
    export interface ExceptionFilter<T = any> {
        catch(exception: T, host: ArgumentsHost): any;
    }
    
    // Custom Exception Filter Ex
    @Catch(CustomHttpException)
    export class CustomHttpExceptionFilter implements ExceptionFilter<CustomHttpException> {
      catch(exception: CustomHttpException, host: ArgumentsHost) {
        const httpArgumentHost = host.switchToHttp();
        const request = ctx.getRequest<Request>();
        const response = ctx.getResponse<Response>();
        const status = exception.getStatus();
    
        response
          .status(status)
          .send();
      }
    }
    @Catch()レコーダが必要なメタデータを異常フィルタにバインドし、通知Exceptionフィルタが対応する処理中NestJs.(@Catch()内で使用可能,複数の例外を入れる.)

    ArgumentHost

    ArgumentHost小包orginal処理手順(異常が発生した箇所)の買収を要請したラッパーです.ここではアプリケーションが使用するプロトコルに従って交換することをサポートするmethodHttpプロトコルが使用されているため、現在switchToHttp()呼び出しにより、返されるhttpArgumentHostからRequestおよびResponseを取得してクライアントの応答をカスタマイズできるようになった.

    フィルタの適用


    前のNesJs pipepipe同様、適用filterと大差ない.
    使用可能filterlevelの3種類に分けられます.

  • Controller-level filter

  • Handler-level filter

  • Global-level filter
  • Controller-level filter


    コントローラレベルでは、@UseFiltersレコーダを使用してExceptionfilterを現在のコントローラに適用できます.
    @Controller()
    @UseFilters(CustomHttpExceptionFilter)
    export class AppController {
        //...
    }

    Handler-level filter


    ハンドルレベルでは、@UseFiltersレコーダを使用してもよいし、このハンドルで発生したException適用filter
    @Get()
    @UseFilters(CustomHttpException)
    getHello(): string {
        throw new CustomHttpException('customException', HttpStatus.BAD_REQUEST);
    }

    Global-level filter


    アプリケーションが起動したmain.tsで設定できます.
    async function bootstrap() {
      const app = await NestFactory.create(AppModule);
      app.useGlobalFilters(new CustomHttpExceptionFilter());
      await app.listen(3000);
    }
    bootstrap();
    または使用可能root Modulecustom Provider適用global filter
    @Module({
      providers: [
        {
          provide: APP_FILTER,
          useClass: CustomHttpExceptionFilter
        }
      ],
    })
    export class AppModule { }
    公式文書によると、filterを適用する場合は、インスタンスではなくクラスを使用することを推奨します.メモリ使用量を減らすためです.(これは、フィルタのインスタンスが単一の色調に保たれているためです.)

    Catch everything


    カスタムで例外を処理する方法について説明しました.指定も可能Exception Filterその方法は不指定@Catch()装飾師argument
    @Catch()
    export class CustomAllExceptionFilter implements ExceptionFilter {
      catch(exception: unknown, host: ArgumentsHost) {
        const ctx = host.switchToHttp();
        const response = ctx.getResponse();
        const request = ctx.getRequest();
    
        const status =
          exception instanceof HttpException
            ? exception.getStatus()
            : HttpStatus.INTERNAL_SERVER_ERROR;
    
        response.status(status).json({
          statusCode: status,
          timestamp: new Date().toISOString(),
          path: request.url,
        });
      }
    }
    上記のように設定すると、未処理Exceptionに対してカスタマイズ処理を行うことができる.

    Reference


  • https://docs.nestjs.com/exception-filters#catch-everything

  • https://jakekwak.gitbook.io/nestjs/overview/untitled