nestjs中异常过滤器Exceptionfilter的具体使用


Posted in Javascript onFebruary 07, 2021

说起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采用了内置的默认异常处理,因此不会出现由于出现未捕获的异常导致程序崩溃。

自定义异常过滤器处理

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

如何自定义异常?

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

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

/**
 * 定义基础异常类
 *
 * @export
 * @class BaseException
 * @extends {HttpException}
 */
export class BaseException extends HttpException {

  /**
   * Creates an instance of BaseException.
   * @param {number} exceptionCode 自定义异常编号
   * @param {string} errorMessage 提示信息
   * @param {number} statusCode 状态码
   * @memberof BaseException
   */
  constructor(public exceptionCode: number, public errorMessage: string, public statusCode: number) {
    super({ exceptionCode: exceptionCode, errorMessage: errorMessage }, statusCode);
  }

  /**
   * 获取自定义异常代码
   *
   * @return {*}
   * @memberof BaseException
   */
  getExceptionCode(): number {
    return this.exceptionCode;
  }

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

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

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

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

export class UnCauhtException extends BaseException {
  constructor() {
    super(40000, "系统运行异常,请联系管理员!", HttpStatus.FORBIDDEN);
  }
}

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

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";

/**
 * 异常基础类过滤器
 *
 * @export
 * @class BaseExceptionFilter
 * @implements {ExceptionFilter<BaseException>}
 */
export abstract class BaseExceptionFilter implements ExceptionFilter<BaseException>
{
  /**
   * 异常类捕获
   *
   * @abstract
   * @param {BaseException} exception
   * @param {ArgumentsHost} host
   * @memberof BaseExceptionFilter
   */
  abstract catch(exception: BaseException, host: ArgumentsHost);

  /**
   * 获取http请求上下文参数
   *
   * @protected
   * @param {ArgumentsHost} host
   * @return {*}
   * @memberof BaseExceptionFilter
   */
  protected getHttpContext(host: ArgumentsHost) {
    return host.switchToHttp();
  }

  /**
   * 获取http 响应参数
   *
   * @protected
   * @param {HttpArgumentsHost} httpContext
   * @return {*}
   * @memberof BaseExceptionFilter
   */
  protected getResponse(httpContext: HttpArgumentsHost): Response {
    return httpContext.getResponse<Response>();
  }

  /**
   * 获取http请求参数
   *
   * @protected
   * @param {HttpArgumentsHost} httpContext
   * @return {*}
   * @memberof BaseExceptionFilter
   */
  protected getRequest(httpContext: HttpArgumentsHost): Request {
    return httpContext.getRequest<Request>();
  }

  /**
   * 写入异常信息到客户端
   *
   * @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: "未处理的异常",
        path: this.getRequest(ctx).url
      });
    }

  }
}

新建未授权异常处理:

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("授权异常构造函数初始化"+new Date().toISOString());
  }
  catch(exception: AuthException, host: ArgumentsHost) {
    exception.exceptionCode=40002;
    console.log("授权异常执行"+new Date().toISOString());
    this.writeToClient(host,exception);
  }

}

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

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

应用范围

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

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';


/**
 * 带有单个路由的基本控制器示例ff
 */
@UseFilters(AuthExceptionFilter,BusinessExceptionFilter)
@Controller()
export class AppController {
 constructor(private readonly appService: AppService) {}

 @Get()
 getHello(): string {
  //throw new Error("666");
  throw new BusinessException("自定义异常",HttpStatus.OK);
  throw new AuthException();
  throw new HttpException("自定义异常",HttpStatus.FORBIDDEN);
  return this.appService.getHello();
 }

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

几点说明:

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

几点疑问

Usefitlers中我们自定义的异常处理类会初始化几次?
答案:我们通过类型注册到Appcontroller的自定义异常类只会在程序初始化的时候初始化一次。也就是说程序启动之后,每个

controller、每个method定义了哪些异常处理类都已经确定。
如果我们捕获到异常,但不进行任何处理,会发生什么?
答案:如果我们的异常处理方法什么也不做,那么恭喜你,会成功的将浏览器请求hang死,因为异常未处理,那么浏览器会一直得不到响应。

多个异常之间的处理顺序如何?
答案:如果多个异常处理均可以捕获到该异常,那么只有第一个有效,也就是说异常处理类和 中间件不同,异常处理类只能其中一个处理,而中间件需要都进行处理。

Nestjs的@Usefilters 像谁?
首先从JS角度来看,像Angular,如果往后端看,最像Spring。 

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

参考文档:docs.nestjs.cn

到此这篇关于nestjs中异常过滤器Exceptionfilter的具体使用的文章就介绍到这了,更多相关nest 异常过滤器Exceptionfilter内容请搜索三水点靠木以前的文章或继续浏览下面的相关文章希望大家以后多多支持三水点靠木!

Javascript 相关文章推荐
利用location.hash实现跨域iframe自适应
May 04 Javascript
javascript实现密码强度显示
Mar 18 Javascript
JS实现的不规则TAB选项卡效果代码
Sep 18 Javascript
Three.js学习之Lamber材质和Phong材质
Aug 04 Javascript
Three.js利用顶点绘制立方体的方法详解
Sep 27 Javascript
深入浅出webpack之externals的使用
Dec 04 Javascript
使用socket.io实现简单聊天室案例
Jan 02 Javascript
jQuery实现鼠标响应式透明度渐变动画效果示例
Feb 13 jQuery
JS实现图片拖拽交换效果
Nov 30 Javascript
用vuex写了一个购物车H5页面的示例代码
Dec 04 Javascript
微信小程序map组件结合高德地图API实现wx.chooseLocation功能示例
Jan 23 Javascript
Vue-input框checkbox强制刷新问题
Apr 18 Javascript
js实现类选择器和name属性选择器的示例步骤
Feb 07 #Javascript
vue如何使用rem适配
Feb 06 #Vue.js
如何管理Vue中的缓存页面
Feb 06 #Vue.js
JS中锚点链接点击平滑滚动并自由调整到顶部位置
Feb 06 #Javascript
一起深入理解js中的事件对象
Feb 06 #Javascript
手动实现vue2.0的双向数据绑定原理详解
Feb 06 #Vue.js
vue3.0 自适应不同分辨率电脑的操作
Feb 06 #Vue.js
You might like
PHP类的静态(static)方法和静态(static)变量使用介绍
2012/02/19 PHP
PHP输出缓存ob系列函数详解
2014/03/11 PHP
php短网址和数字之间相互转换的方法
2015/03/13 PHP
php结合ACCESS的跨库查询功能
2015/06/12 PHP
Javascript JSQL,SQL无处不在,
2010/05/05 Javascript
JavaScript 处理Iframe自适应高度(同或不同域名下)
2013/03/29 Javascript
JS操作数据库的实例代码
2013/10/17 Javascript
Google Maps API地图应用示例分享
2014/10/23 Javascript
JS获取及设置TextArea或input文本框选择文本位置的方法
2015/03/24 Javascript
js采用concat和sort将N个数组拼接起来的方法
2016/01/21 Javascript
Angular.JS中指令ng-if的注意事项小结
2017/06/21 Javascript
JavaScript实现时间表动态效果
2017/07/15 Javascript
ES6中javascript实现函数绑定及类的事件绑定功能详解
2017/11/08 Javascript
Vue实现textarea固定输入行数与添加下划线样式的思路详解
2018/06/28 Javascript
Vue中的验证登录状态的实现方法
2019/03/09 Javascript
24个ES6方法解决JS实际开发问题(小结)
2020/05/31 Javascript
在Python的Django框架中创建语言文件
2015/07/27 Python
Python读取本地文件并解析网页元素的方法
2018/05/21 Python
树莓派实现移动拍照
2019/06/22 Python
Python中的几种矩阵乘法(小结)
2019/07/10 Python
python 多进程共享全局变量之Manager()详解
2019/08/15 Python
python脚本调用iftop 统计业务应用流量的思路详解
2019/10/11 Python
Python3 sys.argv[ ]用法详解
2019/10/24 Python
基于python的列表list和集合set操作
2019/11/24 Python
Python实现bilibili时间长度查询的示例代码
2020/01/14 Python
python中字符串的编码与解码详析
2020/12/03 Python
HTML5实现晶莹剔透的雨滴特效
2014/05/14 HTML / CSS
UGG澳洲官网:UGG Australia
2018/04/26 全球购物
英国第一摩托车和摩托车越野配件商店:GhostBikes
2019/03/10 全球购物
毕业生的自我鉴定该怎么写
2013/12/02 职场文书
超市后勤自我鉴定
2014/01/17 职场文书
九年级物理教学反思
2014/01/29 职场文书
党支部承诺书范文
2014/03/28 职场文书
自我检讨书怎么写
2015/05/07 职场文书
2015年电话客服工作总结
2015/05/18 职场文书
CSS实现隐藏搜索框功能(动画正反向序列)
2021/07/21 HTML / CSS