Application of Exception Filter Exceptionfilter in nestjs

  • 2021-10-25 05:58:05
  • OfStack

Speaking of the exception filter of Nestjs, we can't help but mention the global filter Filter of Net, which is quite powerful in function. In theory, it is called AOP for section programming, which is convenient for too many scenarios requiring exception handling. Back to the exception filter of Nestjs, it implements similar functions and adopts similar handling methods, except that one is for C # and one is for Nodejs. I am honored to find similar things in both frameworks.

Facet-oriented programming AOP, is a similar to the programming specification of the East, the same disciples are called interface-oriented programming, SOLID principles and so on.

Exception Handling of Nestjs

Default exception handling

Nestjs has built-in default global exception filters that handle exceptions that can be converted to Httpexception.

If it is an Httpexception or its subclass exception, the JSON format of the exception is returned:


{"exceptionCode":40005,"message":" Custom exception ","path":"/"}

If it is not an Httpexception or its subclass exception, it will return:


{"statusCode":500,"message":"Internal server error"}

Because Nestjs uses built-in default exception handling, there is no program crash due to an uncaught exception.

Custom Exception Filter Handling

Because the built-in exception handling return value format cannot be adjusted, custom exceptions appear normal again. Custom-defined exception can make the returned exception information custom, and can add custom exception code, which is convenient for client personnel to display different exceptions according to the exception code.

How do I customize exceptions?

It is the programmer's self-discipline not to build wheels repeatedly. First, we create our own exception base class:


import { HttpException } from "@nestjs/common";

/**
 *  Define the underlying exception class 
 *
 * @export
 * @class BaseException
 * @extends {HttpException}
 */
export class BaseException extends HttpException {

  /**
   * Creates an instance of BaseException.
   * @param {number} exceptionCode  Custom exception number 
   * @param {string} errorMessage  Prompt information 
   * @param {number} statusCode  Status code 
   * @memberof BaseException
   */
  constructor(public exceptionCode: number, public errorMessage: string, public statusCode: number) {
    super({ exceptionCode: exceptionCode, errorMessage: errorMessage }, statusCode);
  }

  /**
   *  Get the custom exception code 
   *
   * @return {*}
   * @memberof BaseException
   */
  getExceptionCode(): number {
    return this.exceptionCode;
  }

  getErrorMessage(): string {
    return this.errorMessage;
  }

  getStatusCode(): number {
    return this.statusCode;
  }
}

Then we create a new unauthorized exception type, which adds a custom exception code:


import { HttpStatus } from "@nestjs/common";
import { BaseException } from "./base.exception";

export class UnCauhtException extends BaseException {
  constructor() {
    super(40000, " The system is running abnormally, please contact the administrator! ", HttpStatus.FORBIDDEN);
  }
}

Once the custom exception is established, we need to handle unauthorized exceptions. First, we create a new custom exception handling base class. Please note that we use Express here:


import { ArgumentsHost, ExceptionFilter, HttpException } from "@nestjs/common";
import { HttpArgumentsHost } from "@nestjs/common/interfaces";
import { BaseException } from "src/exceptions/base.exception";
import { Response, Request } from "express";

/**
 *  Exception base class filter 
 *
 * @export
 * @class BaseExceptionFilter
 * @implements {ExceptionFilter<BaseException>}
 */
export abstract class BaseExceptionFilter implements ExceptionFilter<BaseException>
{
  /**
   *  Exception class capture 
   *
   * @abstract
   * @param {BaseException} exception
   * @param {ArgumentsHost} host
   * @memberof BaseExceptionFilter
   */
  abstract catch(exception: BaseException, host: ArgumentsHost);

  /**
   *  Get http Request context parameters 
   *
   * @protected
   * @param {ArgumentsHost} host
   * @return {*}
   * @memberof BaseExceptionFilter
   */
  protected getHttpContext(host: ArgumentsHost) {
    return host.switchToHttp();
  }

  /**
   *  Get http  Response parameter 
   *
   * @protected
   * @param {HttpArgumentsHost} httpContext
   * @return {*}
   * @memberof BaseExceptionFilter
   */
  protected getResponse(httpContext: HttpArgumentsHost): Response {
    return httpContext.getResponse<Response>();
  }

  /**
   *  Get http Request parameter 
   *
   * @protected
   * @param {HttpArgumentsHost} httpContext
   * @return {*}
   * @memberof BaseExceptionFilter
   */
  protected getRequest(httpContext: HttpArgumentsHost): Request {
    return httpContext.getRequest<Request>();
  }

  /**
   *  Write exception information to the client 
   *
   * @param {ArgumentsHost} host
   * @param {BaseException} exception
   * @memberof BaseExceptionFilter
   */
  protected writeToClient(host: ArgumentsHost, exception: BaseException) {
    const ctx = this.getHttpContext(host);
    if(exception instanceof BaseException){
      this.getResponse(ctx).status(exception.statusCode).json({
        exceptionCode: exception.getExceptionCode(),
        message: exception.getErrorMessage(),
        path: this.getRequest(ctx).url
      });
    }else {
      const httpException=exception ;
      this.getResponse(ctx).status(500).json({
        message: " Unhandled exception ",
        path: this.getRequest(ctx).url
      });
    }

  }
}

New Unauthorized Exception Handling:


import { ArgumentsHost, Catch } from "@nestjs/common";
import { AuthException } from "src/exceptions/auth.exception";
import { BaseException } from "src/exceptions/base.exception";
import { BaseExceptionFilter } from "./base.exception.filter";

@Catch(AuthException)
export class AuthExceptionFilter extends BaseExceptionFilter
{
  constructor(){
    super();
    console.log(" Authorization exception constructor initialization "+new Date().toISOString());
  }
  catch(exception: AuthException, host: ArgumentsHost) {
    exception.exceptionCode=40002;
    console.log(" Authorize abnormal execution "+new Date().toISOString());
    this.writeToClient(host,exception);
  }

}

There are several explanations for the unauthorized exception handling class:

Added Catch annotation, only catch Authexception exceptions, other types of exceptions this class does not handle
Inherit the custom exception handling class Baseexceptionfilter

Scope of application

Exception handling classes can be applied to method, controller, global, and even the same Controller can define more than one custom exception class


import { Controller, ForbiddenException, Get, HttpException, HttpStatus, UseFilters } from '@nestjs/common';
import { AppService } from './app.service';
import { AuthException } from './exceptions/auth.exception';
import { BusinessException } from './exceptions/business.exception';
import { UnCauhtException } from './exceptions/uncauht.exception';
import { AuthExceptionFilter } from './filters/auth.exception.filter';
import { BusinessExceptionFilter } from './filters/business.exception.filter';


/**
 *  Example of basic controller with single route ff
 */
@UseFilters(AuthExceptionFilter,BusinessExceptionFilter)
@Controller()
export class AppController {
 constructor(private readonly appService: AppService) {}

 @Get()
 getHello(): string {
  //throw new Error("666");
  throw new BusinessException(" Custom exception ",HttpStatus.OK);
  throw new AuthException();
  throw new HttpException(" Custom exception ",HttpStatus.FORBIDDEN);
  return this.appService.getHello();
 }

 @Get("name")
 getName():string
 {
  return "guozhiqi";
 }
}

A few notes:

We use Usefilters annotations to add exception filters We defined two different types of custom exception handling classes in Appcontroller That is, the exceptions thrown in our Appcontroller can be handled normally as long as they are of these two kinds defined by us.

Some questions

How many times will our custom exception handling class be initialized in Usefitlers?
Answer: The custom exception class we registered with Appcontroller by type will only be initialized once when the program is initialized. That is to say, after the program starts, every

controller, each method defines which exception handling classes have been determined.
What happens if we catch an exception but do nothing to handle it?
Answer: If our exception handling method does nothing, congratulations, it will successfully kill the browser request hang, because the exception is not handled, then the browser will not respond.

What is the processing order between multiple exceptions?
Answer: If multiple exception handlers can catch the exception, then only the first one is valid, which means that the exception handling class is different from middleware, and the exception handling class can only handle one of them, while middleware needs to handle them all.

Who does Nestjs @ Usefilters look like?
First of all, from the perspective of JS, it is like Angular, and if you look back, it is most like Spring.

The exception handling of Nestjs is not complicated. What is complicated is that we need to handle different types of exceptions and extract the commonness of exceptions.

Reference document: docs. nestjs. cn


Related articles: