参考文档: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)

    一.请按要求对YGGL库建立相关索引 (1)使用create index 语句创建索引 1.对employees表中的员工部门号创建普通索引depart_ind. mysql> create i ...

  2. 解决phpmyadmin上传文件大小限制的配置方法

    解决phpmyadmin上传文件大小限制的配置方法 phpmyadmin导入SQL文件时涉及到phpmyadmin上传文件大小限制问题,默认phpmyadmin上传文件大小为2M,如果想要phpmya ...

  3. ping 路由跟踪

    pathping: pathping ip地址/网址 C:\Users\Administrator>pathping 119.29.18.11 通过最多 30 个跃点跟踪到 119.29.18. ...

  4. SQL操作符的优化

    操作符优化        IN 操作符 用IN写出来的SQL的优点是比较容易写及清晰易懂,这比较适合现代软件开发的风格. 但是用IN的SQL性能总是比较低的,从ORACLE执行的步骤来分析用IN的SQ ...

  5. 如何制作sitemaps网站地图

    如何制作sitemaps网站地图 1.0 前言 1.1 xml格式 1.2 常见问题 本文资料来源于网站 1.0 前言 Sitemap 可方便网站管理员通知搜索引擎他们网站上有哪些可供抓取的网页.最简 ...

  6. 使用Python自动填写问卷星(pyppeteer反爬虫版)

    写此文的目的是为了方便寒假自己忘记填问卷星 一开始的想法和去年一样,去年就写过一版,想着今年不过就是改改数据,换换id而已,另外没想到的事情发生了... 满怀信心的写完代码 from selenium ...

  7. 肌肤管家SkinRun V3S智能皮肤检测仪,用AI探索肌肤问题

    继肌肤管家SkinRun V3皮肤检测仪之后,肌肤管家SkinRun近期又一重磅推出的肌肤管家SkinRun V3S 智能肌肤测试仪引起了美业人的广泛关注.据了解它汇集百万皮肤数据,利用五光谱原理和人 ...

  8. maven依赖与传递性依赖

    目录 依赖范围 传递性依赖 依赖调节 可选依赖 本文主要是针对<maven实战>书中关键知识点的学习记录,未免有纰漏或描述不到之处,建议购买阅读原书 首先贴出一个pom常见的一些元素释义 ...

  9. 一次snapshot迁移引发的Hbase RIT(hbase2.1.0-cdh6.3.0)

    1. 问题起因 通过snapshot做跨集群数据同步时,在执行拷贝脚本里没有指定所有者及所有组,导致clone时没有权限,客户端卡死.master一直报错,经过一系列操作后,导致RIT异常. 2. 异 ...

  10. markdown编写文件目录结构

    1.先全局安装tree cnpm i tree-node-cli -g 然后输入: tree --help -L 是确定要几级目录,-I是排除哪个文件夹下的,然后我是要在README里面生成项目结构树 ...