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 相关文章推荐
JSQL 基于客户端的成绩统计实现方法
May 05 Javascript
鼠标左键单击冲突的问题解决方法(防止冒泡)
May 14 Javascript
jQuery自带的一些常用方法总结
Sep 03 Javascript
JS实现先显示大图后自动收起显示小图的广告代码
Sep 04 Javascript
jQuery Validate表单验证深入学习
Dec 18 Javascript
JavaScript setTimeout使用闭包功能实现定时打印数值
Dec 18 Javascript
使用vue.js开发时一些注意事项
Apr 27 Javascript
浅析JavaScript中的对象类型Object
May 26 Javascript
jQuery页面元素动态添加后绑定事件丢失方法,非 live
Jun 16 Javascript
JS简单判断滚动条的滚动方向实现方法
Apr 28 Javascript
Vue2.0中三种常用传值方式(父传子、子传父、非父子组件传值)
Aug 16 Javascript
node.js 使用 net 模块模拟 websocket 握手进行数据传递操作示例
Feb 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
仿Aspnetpager的一个PHP分页类代码 附源码下载
2012/10/08 PHP
在win7中搭建Linux+PHP 开发环境
2014/10/08 PHP
php根据指定位置和长度获得子字符串的方法
2015/03/17 PHP
PHP统计数值数组中出现频率最多的10个数字的方法
2015/04/20 PHP
Thinkphp5结合layer弹窗定制操作结果页面
2017/07/07 PHP
javascript 面向对象编程 聊聊对象的事
2009/09/17 Javascript
JavaScript 页面坐标相关知识整理
2010/01/09 Javascript
GRID拖拽行的实例代码
2013/07/18 Javascript
jquery判断小数点两位和自动删除小数两位后的数字
2014/03/19 Javascript
分享2个jQuery插件--jquery.fileupload与artdialog
2014/12/26 Javascript
jQuery实现联动下拉列表查询框
2017/01/04 Javascript
详谈jQuery中的一些正则匹配表达式
2017/03/08 Javascript
详解vue-cli开发环境跨域问题解决方案
2017/06/06 Javascript
JS实现京东商品分类侧边栏
2020/12/11 Javascript
实例讲解Python爬取网页数据
2018/07/08 Python
Python基于递归算法求最小公倍数和最大公约数示例
2018/07/27 Python
Python之lambda匿名函数及map和filter的用法
2019/03/05 Python
OpenCV图像颜色反转算法详解
2019/05/13 Python
Django 过滤器汇总及自定义过滤器使用详解
2019/07/19 Python
django template实现定义临时变量,自定义赋值、自增实例
2020/07/12 Python
python 还原梯度下降算法实现一维线性回归
2020/10/22 Python
惠普美国官方商店:HP Official Store
2016/08/28 全球购物
世界上最全面的草药补充剂和顶级品牌维生素网站:HerbsPro
2019/01/20 全球购物
澳大利亚最超值的自行车之家:Reid Cycles
2019/03/24 全球购物
Guess荷兰官网:美国服饰品牌
2020/01/22 全球购物
机电专业体育教师求职信
2013/09/21 职场文书
护理学中专毕业生求职信
2013/11/11 职场文书
初一科学教学反思
2014/01/27 职场文书
趣味活动策划方案
2014/02/08 职场文书
开业典礼主持词
2014/03/21 职场文书
股东授权委托书范文
2014/09/13 职场文书
毕业生对母校寄语
2015/02/26 职场文书
python控制台打印log输出重复的解决方法
2021/05/14 Python
利用Python判断你的密码难度等级
2021/06/02 Python
Mysql systemctl start mysqld报错的问题解决
2021/06/03 MySQL
安装Windows Server 2012 R2企业版操作系统并设置好相关参数
2022/04/29 Servers