异常过滤器

在 Nest 中,有一个异常层,它负责捕获未处理的异常,并将适当的响应返回给最终用户。

异常过滤器 - 图1

每个异常都由全局异常筛选器处理, 当无法识别 (不是 HttpException 继承的类 HttpException ) 时, 用户将收到以下 JSON 响应:

  1. {
  2. "statusCode": 500,
  3. "message": "Internal server error"
  4. }

HttpException

HttpException 内 有一个内置的类 @nestjs/common。核心异常处理程序与此类会很好地工作。当你抛出 HttpException 对象时,它将被处理程序捕获并转换为相关的 JSON 响应。

CatsController,我们有一个 create() 方法(POST 路由)。让我们假设这个路由处理器由于某种原因会抛出一个异常。我们要强制编译它:

cats.controller.ts

  1. @Post()
  2. async create(@Body() createCatDto: CreateCatDto) {
  3. throw new HttpException('Forbidden', HttpStatus.FORBIDDEN);
  4. }

!> 我在这里用了 HttpStatus 。这是从 @nestjs/common 包中导入的帮助枚举。

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

  1. {
  2. "statusCode": 403,
  3. "message": "Forbidden"
  4. }

HttpException 构造函数采用 string | object 作为第一个参数。如果您要传递「对象」而不是「字符串」, 则将完全覆盖响应正文。

cats.controller.ts

  1. @Post()
  2. async create(@Body() createCatDto: CreateCatDto) {
  3. throw new HttpException({
  4. status: HttpStatus.FORBIDDEN,
  5. error: 'This is a custom message',
  6. });
  7. }

这就是响应的样子:

  1. {
  2. "status": 403,
  3. "error": "This is a custom message"
  4. }

异常层次(Exceptions Hierarchy)

好的做法是创建自己的异常层次结构。这意味着每个 HTTP 异常都应从基 HttpException 类继承。因此, Nest 将识别您的所有异常, 并将充分注意错误响应。

forbidden.exception.ts

  1. export class ForbiddenException extends HttpException {
  2. constructor() {
  3. super('Forbidden', HttpStatus.FORBIDDEN);
  4. }
  5. }

既然 ForbiddenException 扩展了这个基础 HttpException,它将和核心异常处理程序一起工作,所以我们可以在这个 create() 方法中使用这个类。

cats.controller.ts

  1. @Post()
  2. async create(@Body() createCatDto: CreateCatDto) {
  3. throw new ForbiddenException();
  4. }

HTTP exceptions

为了减少样板代码,Nest 提供了一系列扩展核心的可用异常 HttpException 。所有这些都可以在 @nestjs/common包中找到:

  • BadRequestException
  • UnauthorizedException
  • NotFoundException
  • ForbiddenException
  • NotAcceptableException
  • RequestTimeoutException
  • ConflictException
  • GoneException
  • PayloadTooLargeException
  • UnsupportedMediaTypeException
  • UnprocessableException
  • InternalServerErrorException
  • NotImplementedException
  • BadGatewayException
  • ServiceUnavailableException当
  • GatewayTimeoutException

异常过滤器(Exception Filters)

基本异常处理程序很好,但有时您可能想要完全控制异常层,例如添加一些日志记录或使用不同的 JSON 模式。我们喜欢通用的解决方案,使您的生活更轻松,这就是为什么称为异常过滤器的功能被创建 的原因

我们要创建过滤器,它的职责是抓住 HttpException 并重写 message 属性。

http-exception.filter.ts

  1. import { ExceptionFilter, Catch } from '@nestjs/common';
  2. import { HttpException } from '@nestjs/core';
  3. @Catch(HttpException)
  4. export class HttpExceptionFilter implements ExceptionFilter {
  5. catch(exception: HttpException, response) {
  6. const status = exception.getStatus();
  7. response.status(status).json({
  8. statusCode: status,
  9. message: `It's a message from the exception filter`,
  10. });
  11. }
  12. }

这个 response 是一个原生的 express 对象exception 是当前被处理的异常。

?> 每个异常过滤器都应该实现这个 ExceptionFilter 接口。它强制你提供具有正确特征的 catch()的方法。

所述 @Catch() 装饰结合所需的元数据到异常过滤器。它告诉 Nest,这个过滤器正在寻找 HttpException@Catch() 的参数是无限个数的,所以你可以为多个类型的异常设置该过滤器,只需要用逗号将它们分开。

最后一步是通知 Nest HttpExceptionFilter 应该在 create() 方法内使用。

cats.controller.ts

  1. @Post()
  2. @UseFilters(new HttpExceptionFilter())
  3. async create(@Body() createCatDto: CreateCatDto) {
  4. throw new ForbiddenException();
  5. }

!> @UseFilters() 装饰器从 @nestjs/common 包导入。

我们在 @UseFilters() 这里使用了装饰器。与 @Catch() 相同,它需要无限的参数。

在上面的例子中,HttpExceptionFilter 仅适用于单个 create() 路由处理程序,但它不是唯一的方法。实际上,异常过滤器可以是方法范围的,控制器范围的,也可以是全局范围的。

cats.controller.ts

  1. @UseFilters(new HttpExceptionFilter())
  2. export class CatsController {}

此结构为 CatsController 中的每个路由处理程序设置 HttpExceptionFilter。它是控制器范围的异常过滤器的示例。最后一个可用范围是全局范围的异常过滤器。

server.ts

  1. async function bootstrap() {
  2. const app = await NestFactory.create(ApplicationModule);
  3. app.useGlobalFilters(new HttpExceptionFilter());
  4. await app.listen(3000);
  5. }
  6. bootstrap();

全局过滤器用于整个应用程序,每个控制器,每个路由处理程序。

!> 该 useGlobalFilters() 方法不会为网关和微服务设置过滤器。