【NestJS学习笔记】之 异常 && 异常过滤器

210 阅读7分钟

前言,小编最近在学习NestJS系列相关知识,想把自己了解到的知识点作为笔记的同时也分享给大家,如果有哪里写的不好的恳请各位掘友批评指正谢谢,小编将不胜感激,闲话不多说,我们直接步入正题吧...

一. 在应用程序开发中,抛出异常是一种常见的处理错误和异常情况的方式。异常能够帮助我们识别和处理问题,提高应用程序的可靠性和可维护性。在NestJS中,我们可以利用异常机制来处理各种错误情况。

1.1 基础异常类

Nest提供了一个内置的 HttpException 类,它从 @nestjs/common 包中导入。对于典型的基于HTTP REST/GraphQL API的应用程序,最佳实践是在发生某些错误情况时发送标准HTTP响应对象。
在 CatsController,我们有一个 findAll() 方法(GET 路由)。假设此路由处理程序由于某种原因引发异常。 为了说明这一点,我们在cats.controller.ts中对其进行如下硬编码:

微信图片_20240622204008.png

现在当客户端调用这个端点时,响应如下所示:

微信图片_20240622204242.png

在上面的例子中,我们使用了 HttpStatus 。它是从 @nestjs/common 包导入的辅助枚举器。Nestjs 提供了标准的异常抛出,并且提供了很多的 http status 的定义,这样就不需要记特定的错误代码,只需要找到对应的文字即可。
export declare enum HttpStatus {
    CONTINUE = 100,
    SWITCHING_PROTOCOLS = 101,
    PROCESSING = 102,
    EARLYHINTS = 103,
    OK = 200,
    CREATED = 201,
    ACCEPTED = 202,
    NON_AUTHORITATIVE_INFORMATION = 203,
    NO_CONTENT = 204,
    RESET_CONTENT = 205,
    PARTIAL_CONTENT = 206,
    AMBIGUOUS = 300,
    MOVED_PERMANENTLY = 301,
    FOUND = 302,
    SEE_OTHER = 303,
    NOT_MODIFIED = 304,
    TEMPORARY_REDIRECT = 307,
    PERMANENT_REDIRECT = 308,
    BAD_REQUEST = 400,
    UNAUTHORIZED = 401,
    PAYMENT_REQUIRED = 402,
    FORBIDDEN = 403,
    NOT_FOUND = 404,
    METHOD_NOT_ALLOWED = 405,
    NOT_ACCEPTABLE = 406,
    PROXY_AUTHENTICATION_REQUIRED = 407,
    REQUEST_TIMEOUT = 408,
    CONFLICT = 409,
    GONE = 410,
    LENGTH_REQUIRED = 411,
    PRECONDITION_FAILED = 412,
    PAYLOAD_TOO_LARGE = 413,
    URI_TOO_LONG = 414,
    UNSUPPORTED_MEDIA_TYPE = 415,
    REQUESTED_RANGE_NOT_SATISFIABLE = 416,
    EXPECTATION_FAILED = 417,
    I_AM_A_TEAPOT = 418,
    MISDIRECTED = 421,
    UNPROCESSABLE_ENTITY = 422,
    FAILED_DEPENDENCY = 424,
    PRECONDITION_REQUIRED = 428,
    TOO_MANY_REQUESTS = 429,
    INTERNAL_SERVER_ERROR = 500,
    NOT_IMPLEMENTED = 501,
    BAD_GATEWAY = 502,
    SERVICE_UNAVAILABLE = 503,
    GATEWAY_TIMEOUT = 504,
    HTTP_VERSION_NOT_SUPPORTED = 505
}

HttpException 构造函数有两个必要的参数来决定响应:

  • response 参数定义 JSON 响应体。它可以是 string 或 object,如下所述。
  • status参数定义HTTP状态代码

默认情况下,JSON 响应主体包含两个属性:

  • statusCode:默认为 status 参数中提供的 HTTP 状态代码
  • message:基于状态的 HTTP 错误的简短描述

仅覆盖 JSON 响应主体的消息部分,请在 response参数中提供一个 string

要覆盖整个 JSON 响应主体,请在response 参数中传递一个object。 Nest将序列化对象,并将其作为JSON 响应返回。

第二个构造函数参数-status-是有效的 HTTP 状态代码。 最佳实践是使用从@nestjs/common导入的 HttpStatus枚举。

这是一个覆盖整个响应正文的示例:

微信图片_20240622205650.png

使用上面的代码,响应如下所示:

微信图片_20240622205653.png

1.2 自定义异常

对 Nestjs 的 HttpException 进行封装就可以自己定我们想要的异常抛出类。使用这种方法,Nest可以识别我们自定义的异常,并自动处理错误响应。 让我们实现这样一个自定义异常:

微信图片_20240622211228.png

由于 ForbiddenException 扩展了基础 HttpException,它将和核心异常处理程序一起工作,因此我们可以在 findAll()方法中使用它。

微信图片_20240622205406.png

使用上面的代码,响应如下所示:

微信图片_20240622205653.png

二. 异常过滤器

虽然基本(内置)异常过滤器可以为我们自动处理许多情况,但有时我们可能希望对异常层拥有完全控制权,例如,可能希望基于某些动态因素添加日志记录或使用不同的 JSON 模式。 异常过滤器正是为此目的而设计的。 它们可以控制精确的控制流以及将响应的内容发送回客户端。
让我们创建一个异常过滤器,它负责捕获作为HttpException类实例的异常,并为它们设置自定义响应逻辑。为此,我们需要访问底层平台 Request和 Response。我们将访问Request对象,以便提取原始 url并将其包含在日志信息中。我们将使用 Response.json()方法,使用 Response对象直接控制发送的响应。

微信图片_20240622211911.png

所有异常过滤器都应该实现通用的 ExceptionFilter<T> 接口。它需要我们使用有效签名提供 catch(exception: T, host: ArgumentsHost)方法。T 表示异常的类型。@Catch() 装饰器绑定所需的元数据到异常过滤器上。它告诉 Nest这个特定的过滤器正在寻找 HttpException 而不是其他的。在实践中,@Catch() 可以传递多个参数,所以我们可以通过逗号分隔来为多个类型的异常设置过滤器。
绑定过滤器:让我们将 HttpExceptionFilter 绑定到 CatsController 的 create() 方法上。@UseFilters() 装饰器需要从 @nestjs/common 包导入。

微信图片_20240622212938.png

绑定该过滤器之后的响应结果如下:

微信图片_20240622212842.png

我们在上面使用了 @UseFilters() 装饰器。和 @Catch()装饰器类似,它可以使用单个过滤器实例,也可以使用逗号分隔的过滤器实例列表。 我们创建了 HttpExceptionFilter 的实例。另一种可用的方式是传递类(不是实例),让框架承担实例化责任并启用依赖注入。尽可能使用类而不是实例。由于 Nest 可以轻松地在整个模块中重复使用同一类的实例,因此可以减少内存使用
推荐写法:

微信图片_20240622213439.png

在上面的示例中,HttpExceptionFilter 仅应用于单个 create() 路由处理程序,使其成为方法范围的。 异常过滤器的作用域可以划分为不同的级别:方法范围,控制器范围或全局范围。 上面演示的是方法范围的过滤器,下面逐一举例
控制器范围,此结构为 CatsController 中的每个路由处理程序设置 HttpExceptionFilter

微信图片_20240622214113.png

全局范围的过滤器:全局过滤器用于整个应用程序、每个控制器和每个路由处理程序。

微信图片_20240622214116.png

就依赖注入而言,从任何模块外部注册的全局过滤器(使用上面示例中的 useGlobalFilters())不能注入依赖,因为它们不属于任何模块。为了解决这个问题,我们可以注册一个全局范围的过滤器直接为我们想要的模块设置过滤器,以根据需要将不同的过滤器应用于不同的模块,实现更细粒度的异常处理:

微信图片_20240622220000.png

需要注意的是,如果同时在main.tsapp.module.ts中注册了相同的过滤器,全局注册的过滤器将具有更高的优先级,即会覆盖模块级注册的过滤器。

2.1 捕获异常

为了捕获每一个未处理的异常(不管异常类型如何),将 @Catch() 装饰器的参数列表设为空,例如 @Catch()

微信图片_20240622220409.png

以上就是 Nestjs 中抛出异常的方法,包括了基础异常抛出和自定义异常抛出以及异常处理器,感谢阅读!!!

参考:大佬web前端的markzzw的【Nestjs学习日记】抛出异常