2021-02-06

Nodejs Nestjs 路程 之 异常过滤器Exceptionfilter

Nestjs

参考文档:docs.nestjs.cn

说起Nestjs的异常过滤器,不能不提.Net的全局过滤器Filter,功能那是相当的强悍,用理论话说叫AOP 面向切面编程,可谓方便了太多需要异常处理的场景。说回Nestjs的异常过滤器,实现类似的功能,采用相似的处理方式,只不过一个面向C#,一个面向Nodejs,很荣幸的我,在两个框架都找到了类似的东西。

面向切面编程AOP,是一种类似于编程规范的东东,同门师兄弟有叫面向接口编程、SOLID原则等等。

Nestjs的异常处理

默认异常处理

Nestjs内置了默认的全局异常过滤器,处理能够转换成Httpexception的异常。

如果是Httpexception或其子类异常,那么会返回该异常的JSON格式:

{"exceptionCode":40005,"message":"自定义异常","path":"/"}

如果不是Httpexception或其子类异常,那么会返回:

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

由于Nestjs采用了内置的默认异常处理,因此不会出现由于出现未捕获的异常导致程序崩溃。

 

自定义异常过滤器处理

由于内置异常处理返回值格式无法调整,因此自定义异常就显得又为正常。自定义异常可以使返回异常信息自定义,且可以增加自定义异常编码,方便客户端人员根据异常编码进行不同的展示。

如何自定义异常?

不重复造轮子是程序员的自我约束,首先我们新建我们自己的异常基类:

 1 import { HttpException } from "@nestjs/common"; 2  3 /** 4  * 定义基础异常类 5  * 6  * @export 7  * @class BaseException 8  * @extends {HttpException} 9 */10 export class BaseException extends HttpException {11 12  /**13   * Creates an instance of BaseException.14   * @param {number} exceptionCode 自定义异常编号15   * @param {string} errorMessage 提示信息16   * @param {number} statusCode 状态码17   * @memberof BaseException18  */19  constructor(public exceptionCode: number, public errorMessage: string, public statusCode: number) {20   super({ exceptionCode: exceptionCode, errorMessage: errorMessage }, statusCode);  21  }22 23  /**24   * 获取自定义异常代码25   *26   * @return {*} 27   * @memberof BaseException28  */29  getExceptionCode(): number {30   return this.exceptionCode;31  }32 33  getErrorMessage(): string {34   return this.errorMessage;35  }36 37  getStatusCode(): number {38   return this.statusCode;39  }40 }

然后我们新建一个未授权异常类型,其中增加了自定义异常代码:

1 import { HttpStatus } from "@nestjs/common";2 import { BaseException } from "./base.exception";3 4 export class UnCauhtException extends BaseException {5  constructor() {6   super(40000, "系统运行异常,请联系管理员!", HttpStatus.FORBIDDEN);7  }8 }

建立好了自定义异常,那么我们就需要处理未授权异常,首先新建自定义异常处理基类,请注意 此处我们使用的事Express:

 1 import { ArgumentsHost, ExceptionFilter, HttpException } from "@nestjs/common"; 2 import { HttpArgumentsHost } from "@nestjs/common/interfaces"; 3 import { BaseException } from "src/exceptions/base.exception"; 4 import { Response, Request } from "express"; 5  6 /** 7  * 异常基础类过滤器 8  * 9  * @export10  * @class BaseExceptionFilter11  * @implements {ExceptionFilter<BaseException>}12 */13 export abstract class BaseExceptionFilter implements ExceptionFilter<BaseException>14 {15  /**16   * 异常类捕获17   *18   * @abstract19   * @param {BaseException} exception20   * @param {ArgumentsHost} host21   * @memberof BaseExceptionFilter22  */23  abstract catch(exception: BaseException, host: ArgumentsHost);24 25  /**26   * 获取http请求上下文参数27   *28   * @protected29   * @param {ArgumentsHost} host30   * @return {*} 31   * @memberof BaseExceptionFilter32  */33  protected getHttpContext(host: ArgumentsHost) {34   return host.switchToHttp();35  }36 37  /**38   * 获取http 响应参数39   *40   * @protected41   * @param {HttpArgumentsHost} httpContext42   * @return {*} 43   * @memberof BaseExceptionFilter44  */45  protected getResponse(httpContext: HttpArgumentsHost): Response {46   return httpContext.getResponse<Response>();47  }48 49  /**50   * 获取http请求参数51   *52   * @protected53   * @param {HttpArgumentsHost} httpContext54   * @return {*} 55   * @memberof BaseExceptionFilter56  */57  protected getRequest(httpContext: HttpArgumentsHost): Request {58   return httpContext.getRequest<Request>();59  }60 61  /**62   * 写入异常信息到客户端63   *64   * @param {ArgumentsHost} host65   * @param {BaseException} exception66   * @memberof BaseExceptionFilter67  */68  protected writeToClient(host: ArgumentsHost, exception: BaseException) {69   const ctx = this.getHttpContext(host);70   if(exception instanceof BaseException){   71    this.getResponse(ctx).status(exception.statusCode).json({72     exceptionCode: exception.getExceptionCode(),73     message: exception.getErrorMessage(),74     path: this.getRequest(ctx).url75    });76   }else {77    const httpException=exception ;78    this.getResponse(ctx).status(500).json({    79     message: "未处理的异常",80     path: this.getRequest(ctx).url81    });82   }83   84  }85 }

新建未授权异常处理:

 1 import { ArgumentsHost, Catch } from "@nestjs/common"; 2 import { AuthException } from "src/exceptions/auth.exception"; 3 import { BaseException } from "src/exceptions/base.exception"; 4 import { BaseExceptionFilter } from "./base.exception.filter"; 5  6 @Catch(AuthException) 7 export class AuthExceptionFilter extends BaseExceptionFilter 8 { 9  constructor(){10   super();11   console.log("授权异常构造函数初始化"+new Date().toISOString());12  }13  catch(exception: AuthException, host: ArgumentsHost) {14   exception.exceptionCode=40002;15   console.log("授权异常执行"+new Date().toISOString());16   this.writeToClient(host,exception);17  }18  19 }

针对未授权异常处理类,进行几点说明:

  1. 增加了Catch注解,只捕获Authexception的异常,其他类型的异常此类不进行处理
  2. 继承自定义异常处理类Baseexceptionfilter

应用范围

异常处理类可应用于method、controller、全局,甚至同一个Controller可以定义多个自定义异常类

 1 import { Controller, ForbiddenException, Get, HttpException, HttpStatus, UseFilters } from '@nestjs/common'; 2 import { AppService } from './app.service'; 3 import { AuthException } from './exceptions/auth.exception'; 4 import { BusinessException } from './exceptions/business.exception'; 5 import { UnCauhtException } from './exceptions/uncauht.exception'; 6 import { AuthExceptionFilter } from './filters/auth.exception.filter'; 7 import { BusinessExceptionFilter } from './filters/business.exception.filter'; 8  9 10 /**11  * 带有单个路由的基本控制器示例ff12 */13 @UseFilters(AuthExceptionFilter,BusinessExceptionFilter)14 @Controller()15 export class AppController {16  constructor(private readonly appService: AppService) {}17 18  @Get()19  getHello(): string { 20  //throw new Error("666");21  throw new BusinessException("自定义异常",HttpStatus.OK);22  throw new AuthException();23  throw new HttpException("自定义异常",HttpStatus.FORBIDDEN);24  return this.appService.getHello();25  }26 27 @Get("name")28  getName():string29  {30  return "guozhiqi";31  }32 }

几点说明:

  1. 我们使用Usefilters注解进行异常过滤器的添加
  2. 我们在Appcontroller中定义了两种不同类型的自定义异常处理类
  3. 也就是我们Appcontroller中抛出的异常,只要是我们定义的这两种,那么都可以被正常处理。

几点疑问

  1. Usefitlers中我们自定义的异常处理类会初始化几次?
    答案:我们通过类型注册到Appcontroller的自定义异常类只会在程序初始化的时候初始化一次。也就是说程序启动之后,每个controller、每个method定义了哪些异常处理类都已经确定。
  2. 如果我们捕获到异常,但不进行任何处理,会发生什么?
    答案:如果我们的异常处理方法什么也不做,那么恭喜你,会成功的将浏览器请求hang死,因为异常未处理,那么浏览器会一直得不到响应。
  3. 多个异常之间的处理顺序如何?
    答案:如果多个异常处理均可以捕获到该异常,那么只有第一个有效,也就是说异常处理类和 中间件不同,异常处理类只能其中一个处理,而中间件需要都进行处理。
  4. Nestjs的@Usefilters 像谁?
    首先从JS角度来看,像Angular,如果往后端看,最像Spring。

 

Nestjs的异常处理并不复杂,复杂的是需要我们针对不同类型的异常进行处理,提取异常的共性。









原文转载:http://www.shaoqun.com/a/533565.html

跨境电商:https://www.ikjzd.com/

黑石集团:https://www.ikjzd.com/w/1339.html

兰亭集势:https://www.ikjzd.com/w/820


Nestjs参考文档:docs.nestjs.cn说起Nestjs的异常过滤器,不能不提.Net的全局过滤器Filter,功能那是相当的强悍,用理论话说叫AOP面向切面编程,可谓方便了太多需要异常处理的场景。说回Nestjs的异常过滤器,实现类似的功能,采用相似的处理方式,只不过一个面向C#,一个面向Nodejs,很荣幸的我,在两个框架都找到了类似的东西。面向切面编程AOP,是一种类似于编程规范的
patents:patents
ola:ola
(精品分析)亚马逊德国站男装上衣类目市场调查数据报告:(精品分析)亚马逊德国站男装上衣类目市场调查数据报告
"赶跟卖"须慎重,从一位亚马逊卖家的心酸往事说起:"赶跟卖"须慎重,从一位亚马逊卖家的心酸往事说起
国内电商市场饱和,转战跨境电商新手如何提升,从哪下手更稳当?:国内电商市场饱和,转战跨境电商新手如何提升,从哪下手更稳当?

No comments:

Post a Comment