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 相关文章推荐
jQuery的初始化与对象构建之浅析
Apr 12 Javascript
为EasyUI的Tab标签添加右键菜单的方法
Jul 14 Javascript
jQuery 选择表格(table)里的行和列及改变简单样式
Dec 15 Javascript
js中如何把字符串转化为对象、数组示例代码
Jul 17 Javascript
javascript实现支持移动设备画廊
Aug 24 Javascript
在Web项目中引入Jquery插件报错的完美解决方案(图解)
Sep 19 Javascript
Vue实现数字输入框中分割手机号码的示例
Oct 10 Javascript
详解webpack-dev-server 设置反向代理解决跨域问题
Apr 18 Javascript
vue使用jsonp抓取qq音乐数据的方法
Jun 21 Javascript
详解使用element-ui table组件的筛选功能的一个小坑
Nov 02 Javascript
Vue+Element实现动态生成新表单并添加验证功能
May 23 Javascript
JavaScript 判断数据类型的4种方法
Sep 11 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的图形函数中显示汉字
2006/10/09 PHP
抓取YAHOO股票报价的类
2009/05/15 PHP
一些php技巧与注意事项分析
2011/02/03 PHP
腾讯QQ微博API接口获取微博内容
2013/10/30 PHP
zf框架的数据库追踪器使用示例
2014/03/13 PHP
CI框架给视图添加动态数据
2014/12/01 PHP
PHP实现将textarea的值根据回车换行拆分至数组
2015/06/10 PHP
JavaScript常用全局属性与方法记录积累
2013/07/03 Javascript
jquery选择checked在ie8普通模式下的问题
2014/02/12 Javascript
js实现文本框中焦点在最后位置
2014/03/04 Javascript
深入探讨前端框架react
2015/12/09 Javascript
javascript中new关键字详解
2015/12/14 Javascript
Node.js服务器环境下使用Mock.js拦截AJAX请求的教程
2016/05/23 Javascript
jQ处理xml文件和xml字符串的方法(详解)
2016/11/22 Javascript
Node.js 回调函数实例详解
2017/07/06 Javascript
详解Webpack+Babel+React开发环境的搭建的方法步骤
2018/01/09 Javascript
微信小程序实现动态列表项的顺序加载动画
2019/07/25 Javascript
JS代码触发事件代码实例
2020/01/02 Javascript
在Vuex中Mutations修改状态操作
2020/07/24 Javascript
python实现DNS正向查询、反向查询的例子
2014/04/25 Python
python3使用PyMysql连接mysql数据库实例
2017/02/07 Python
Pandas 对Dataframe结构排序的实现方法
2018/04/10 Python
python traceback捕获并打印异常的方法
2018/08/31 Python
python中的句柄操作的方法示例
2019/06/20 Python
TensorFlow2.0矩阵与向量的加减乘实例
2020/02/07 Python
HTML最新标准HTML5总结(必看)
2016/06/13 HTML / CSS
诗狄娜化妆品官方网站:Stila Cosmetics
2016/12/21 全球购物
医药销售求职信范文
2014/02/01 职场文书
医学专业职业生涯规划范文
2014/02/05 职场文书
小学先进集体事迹材料
2014/05/31 职场文书
保护环境的标语
2014/06/09 职场文书
2014年平安建设工作总结
2014/11/19 职场文书
我的长征观后感
2015/06/09 职场文书
新课程改革心得体会
2016/01/22 职场文书
幼儿园小班教学反思
2016/03/03 职场文书
PL350与SW11的比较
2021/04/22 无线电