参考文档: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 BaseException
18 */
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 BaseException
28 */
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 * @export
10 * @class BaseExceptionFilter
11 * @implements {ExceptionFilter<BaseException>}
12 */
13 export abstract class BaseExceptionFilter implements ExceptionFilter<BaseException>
14 {
15 /**
16 * 异常类捕获
17 *
18 * @abstract
19 * @param {BaseException} exception
20 * @param {ArgumentsHost} host
21 * @memberof BaseExceptionFilter
22 */
23 abstract catch(exception: BaseException, host: ArgumentsHost);
24
25 /**
26 * 获取http请求上下文参数
27 *
28 * @protected
29 * @param {ArgumentsHost} host
30 * @return {*}
31 * @memberof BaseExceptionFilter
32 */
33 protected getHttpContext(host: ArgumentsHost) {
34 return host.switchToHttp();
35 }
36
37 /**
38 * 获取http 响应参数
39 *
40 * @protected
41 * @param {HttpArgumentsHost} httpContext
42 * @return {*}
43 * @memberof BaseExceptionFilter
44 */
45 protected getResponse(httpContext: HttpArgumentsHost): Response {
46 return httpContext.getResponse<Response>();
47 }
48
49 /**
50 * 获取http请求参数
51 *
52 * @protected
53 * @param {HttpArgumentsHost} httpContext
54 * @return {*}
55 * @memberof BaseExceptionFilter
56 */
57 protected getRequest(httpContext: HttpArgumentsHost): Request {
58 return httpContext.getRequest<Request>();
59 }
60
61 /**
62 * 写入异常信息到客户端
63 *
64 * @param {ArgumentsHost} host
65 * @param {BaseException} exception
66 * @memberof BaseExceptionFilter
67 */
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).url
75 });
76 }else {
77 const httpException=exception ;
78 this.getResponse(ctx).status(500).json({
79 message: "未处理的异常",
80 path: this.getRequest(ctx).url
81 });
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 * 带有单个路由的基本控制器示例ff
12 */
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():string
29 {
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的异常处理并不复杂,复杂的是需要我们针对不同类型的异常进行处理,提取异常的共性。

Nestjs 路程 之 异常过滤器Exceptionfilter的更多相关文章

  1. asp.net core MVC 全局过滤器之ExceptionFilter异常过滤器(一)

    本系类将会讲解asp.net core MVC中的内置全局过滤器的使用,将分为以下章节 asp.net core MVC 过滤器之ExceptionFilter异常过滤器(一) asp.net cor ...

  2. MVC异常日志生产者消费者模式记录(异常过滤器)

    生产者消费者模式 定义自己的异常过滤器并注册 namespace Eco.Web.App.Models { public class MyExceptionAttribute : HandleErro ...

  3. MVC 全局异常过滤器HandleErrorAttribute

    using System; using System.Collections.Generic; using System.Linq; using System.Web; using System.We ...

  4. 笨鸟先飞之ASP.NET MVC系列之过滤器(06异常过滤器)

    概念介绍 异常过滤器主要在我们方法中出现异常的时候触发,一般我们用 异常过滤器 记录日志,或者在产生异常时做友好的处理 如果我们需要创建异常过滤器需要实现IExceptionFilter接口. nam ...

  5. MVC教程九:异常过滤器

    我们平常在程序里面为了捕获异常,会加上try-catch-finally代码,但是这样会使得程序代码看起来很庞大,在MVC中我们可以使用异常过滤器来捕获程序中的异常,如下图所示: 使用了异常过滤器以后 ...

  6. [Asp.net MVC]HandleErrorAttribute异常过滤器

    摘要 在asp.net mvc中除了使用try...catch/finally来处理异常外,它提供了一种通过在Controller或者Action上添加特性的方式来处理异常. HandleErrorA ...

  7. MVC与WebApi中的异常过滤器

    一.MVC的异常过滤器   1.自定义MVC异常过滤器 创建一个类,继承HandleErrorAttribute即可,如果不需要作为特性使用直接实现IExceptionFilter接口即可, 注意,该 ...

  8. MVC异常过滤器 (错误页)

    控制器 using System; using System.Collections.Generic; using System.Linq; using System.Web; using Syste ...

  9. MVC异常过滤器

    MVC过滤器 一般的过滤器执行顺序 IAuthorizationFilter->OnAuthorization(授权) IActionFilter          ->OnActionE ...

随机推荐

  1. 关于一些视图的基本操作(结合YGGL.sql)

    二.操作题 1.创建视图emp_view2,包含员工编号,姓名,所在部门名称和收入. mysql> create or replace view emp_view2 -> as -> ...

  2. 阿里云centos7[linux]安装nginx

    标题 说明 服务器版本 Centos7 x64 nginx版本 1.19.6 作者 walton 一.准备 创建安装包目录并进入 mkdir /usr/dev/nginx cd /usr/dev/ng ...

  3. Syn_Flood攻击&防御手段

    Syn_Flood攻击原理 攻击者首先伪造地址对服务器发起SYN请求(我可以建立连接吗?),服务器就会回应一个ACK+SYN(可以+请确认).而真实的IP会认为,我没有发送请求,不作回应.服务器没有收 ...

  4. fastjson复现项目代码

    详情请见:https://www.cnblogs.com/yunmuq/p/14268028.html 以下是代码 // FastjsonDemo.java package test; import ...

  5. Unity 编辑器(移除missing)

    移除 Missing(Mono Script) ` private static void FindMissingReferences() { GameObject[] pAllObjects = ( ...

  6. 【Flutter】功能型组件之导航返回拦截

    前言 为了避免用户误触返回按钮而导致APP退出,在很多APP中都拦截了用户点击返回键的按钮,然后进行一些防误触判断,比如当用户在某一个时间段内点击两次时,才会认为用户是要退出(而非误触).Flutte ...

  7. 我们NetCore下日志存储设计

    日志的分类 首先往大的来说,日志分2种 ①业务日志: 即业务系统需要查看的日志, 常见的比如谁什么时候修改了什么. ②参数日志: 一般是开发人员遇到问题的时候定位用的, 一般不需要再业务系统里展示. ...

  8. VBA实现相同行合并

    帮人捣鼓了个VBA代码用来实现多行合并,具体需求为:列2/列3/列4 相同的情况下,则对应的行合并为一行,且列1用空格隔开,列5则相加: (对大多数办公室职员,VBA还算是提高效率的一个利器吧) 最终 ...

  9. Hbase RIT故障修复

    业务场景: RocketMQ+Storm+Hbase 组件版本: RocketMQ:3.4.6 Storm:1.2.1 Hbase:1.2.1 1. 问题描述 4月15号早上发现业务系统前一天数据量明 ...

  10. 【Spring】Spring的数据库开发 - 2、Spring JdbcTemplate的常用方法(execute、update、query)

    Spring JdbcTemplate的常用方法 文章目录 Spring JdbcTemplate的常用方法 execute() update() query() 简单记录-Java EE企业级应用开 ...