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 相关文章推荐
HTML 自动伸缩的表格Table js实现
Apr 01 Javascript
IE与Firefox在JavaScript上的7个不同写法小结
Sep 14 Javascript
使用js判断TextBox控件值改变然后出发事件
Mar 07 Javascript
jQuery检测输入的字符串包含的中英文的数量
Apr 17 Javascript
Javascript封装id、class与元素选择器方法示例
Mar 13 Javascript
jquery平滑滚动到顶部插件使用详解
May 08 jQuery
jQuery实现的弹幕效果完整实例
Sep 06 jQuery
JavaScript门面模式详解
Oct 19 Javascript
express默认日志组件morgan的方法
Apr 05 Javascript
Vue.js 2.x之组件的定义和注册图文详解
Jun 19 Javascript
解决vue 给window添加和移除resize事件遇到的坑
Jul 21 Javascript
使用Vant完成Dialog弹框案例
Nov 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
用正则xmlHttp实现的偷(转)
2007/01/22 Javascript
javascript基础第一章 JavaScript与用户端
2010/07/22 Javascript
JavaScript Array Flatten 与递归使用介绍
2011/10/30 Javascript
jquery分页插件jpaginate在IE中不兼容问题
2014/04/22 Javascript
Javascript中设置默认参数值示例
2014/09/11 Javascript
bootstrap改变按钮加载状态
2014/12/01 Javascript
jquery+html5制作超酷的圆盘时钟表
2015/04/14 Javascript
jQuery固定元素插件scrolltofixed使用指南
2015/04/21 Javascript
jQuery实现自动调整字体大小的方法
2015/06/15 Javascript
浅谈Node异步编程的机制
2017/10/18 Javascript
JavaScript数组排序的六种常见算法总结
2020/08/18 Javascript
基于vue-simple-uploader封装文件分片上传、秒传及断点续传的全局上传插件功能
2021/02/23 Vue.js
[02:26]2018DOTA2亚洲邀请赛赛前采访-Newbee篇
2018/04/03 DOTA
[50:27]Secret vs VG 2018国际邀请赛小组赛BO2 第二场 8.17
2018/08/20 DOTA
python使用opencv进行人脸识别
2017/04/07 Python
基于python requests库中的代理实例讲解
2018/05/07 Python
浅析PHP与Python进行数据交互
2018/05/15 Python
基于python实现百度翻译功能
2019/05/09 Python
python实现可变变量名方法详解
2019/07/01 Python
Python之修改图片像素值的方法
2019/07/03 Python
Tensorflow: 从checkpoint文件中读取tensor方式
2020/02/10 Python
500行python代码实现飞机大战
2020/04/24 Python
Python flask框架如何显示图像到web页面
2020/06/03 Python
keras.utils.to_categorical和one hot格式解析
2020/07/02 Python
两只小狮子教学反思
2014/02/05 职场文书
药店主任岗位责任制
2014/02/10 职场文书
致100米运动员广播稿
2014/02/14 职场文书
民族团结演讲稿范文
2014/08/27 职场文书
个人学习党的群众路线教育实践活动心得体会
2014/11/05 职场文书
初中教师个人工作总结
2015/02/10 职场文书
2015年司机年终工作总结
2015/05/14 职场文书
学校证明范文
2015/06/24 职场文书
学雷锋活动简报
2015/07/20 职场文书
8g内存用python读取10文件_面试题-python 如何读取一个大于 10G 的txt文件?
2021/05/28 Python
使用Redis实现点赞取消点赞的详细代码
2022/03/20 Redis
Python写情书? 10行代码展示如何把情书写在她的照片里
2022/04/21 Python