【Nest】异常处理

2021/09/07 11:30:01

抛出异常

直接用 throw 关键字抛出即可。

import { Controller, All, HttpException, HttpStatus } from "@nestjs/common";

@Controller()
export class AppController {
  @All()
  findAll() {
    throw new HttpException(
      {
        code: -1,
        msg: "Forbidden",
        result: false,
      },
      HttpStatus.BAD_REQUEST
    );
  }
}

异常类型

Nest 的异常类型包括基础异常类(HttpException)、自定义异常类(继承自 HttpException)和内置异常。

基础异常类

Nest 提供了一个内置的 HttpException 类,它从 @nestjs/common 包中导入。

import { HttpException } from "@nestjs/common";

自定义异常

自定义异常需要继承 HttpException 类。

  • forbidden.exception.ts
import { HttpException } from "@nestjs/common";

export class ForbiddenException extends HttpException {
  constructor() {
    super("Forbidden", HttpStatus.FORBIDDEN);
  }
}

异常过滤器

虽然基本(内置)异常过滤器可以为您自动处理许多情况,但有时您可能希望对异常层拥有完全控制权,例如,您可能要添加日志记录或基于一些动态因素使用其他 JSON 模式。 异常过滤器正是为此目的而设计的。 它们使您可以控制精确的控制流以及将响应的内容发送回客户端。

在异常过滤器中可以访问底层平台 Request 和 Response,实现更复杂的逻辑。

定义异常过滤器

  • http-exception.filter.ts
import { ExceptionFilter, Catch, ArgumentsHost, HttpException } from '@nestjs/common';
import { Request, Response } from 'express';

@Catch(HttpException)
export class HttpExceptionFilter implements ExceptionFilter {
  catch(exception: HttpException, host: ArgumentsHost) {
    const ctx = host.switchToHttp();
    const response = ctx.getResponse<Response>();
    const request = ctx.getRequest<Request>();
    const status = exception.getStatus();

    response
      .status(status)
      .json({
        statusCode: status,
        timestamp: new Date().toISOString(),
        path: request.url,
      });
  }
}

绑定过滤器

使用 @UseFilters() 装饰器来注册过滤器。

  • app.controller.ts
import { Controller, All, HttpException, HttpStatus, UseFilters } from '@nestjs/common';

import { HttpExceptionFilter } from './filter/http-exception.filter'
@Controller()
export class AppController {
  @All()
  @UseFilters(HttpExceptionFilter)
  findAll() {
    throw new HttpException('normal error', HttpStatus.BAD_REQUEST);
  }
}

异常过滤器的作用域

异常过滤器的作用域可以划分为不同的级别:方法范围,控制器范围或全局范围。

在方法上使用 @UseFilters() 装饰器为方法范围的过滤器。

  • app.controller.ts
@All()
@UseFilters(HttpExceptionFilter)
findAll() {
    throw new HttpException('normal error', HttpStatus.BAD_REQUEST);
}

在控制器类上使用 @UseFilters() 装饰器为控制器范围的过滤器。

  • app.controller.ts
@Controller()
@UseFilters(HttpExceptionFilter)
export class AppController {
  @All()
  findAll() {
    throw new HttpException('normal error', HttpStatus.BAD_REQUEST);
  }
}

全局范围的过滤器需要在根 module 上绑定

  • app.module.js
async function bootstrap() {
  const app = await NestFactory.create(AppModule);
  app.useGlobalFilters(new HttpExceptionFilter());
  await app.listen(3000);
}
bootstrap();