Nestjs(五)异常处理方式(异常过滤器)

126 阅读2分钟

一、简介

  • 异常过滤器 - 官方文档

  • 创建异常过滤器 http-exception.filter.ts 文件

    $ nest g f http-exception
    
    // 这是创建后的文件初始内容
    import { ArgumentsHost, Catch, ExceptionFilter } from '@nestjs/common';
    
    @Catch()
    export class HttpExceptionFilter<T> implements ExceptionFilter {
      catch(exception: T, host: ArgumentsHost) {
        // 这里就是拦截到的异常,需要处理并抛出给到前台方便直观看到问题...
        // 输出拦截到的错误异常
        console.log(exception)
      }
    }
    
  • 做下小改造,上面初始化的只会在 node 控制台输出,现在改造成将这个异常抛出到接口返回,前端接口就能看得到:

    import { ArgumentsHost, Catch, ExceptionFilter, HttpException } from '@nestjs/common';
    // 如果不引用,可能会导致类型关联错误
    import { Response, Request } from 'express';
    
    // 捕获 HttpException 错误;  如果 @Catch() 里面没有参数, 则捕获所有错误
    // 可以支持多个 @Catch(HttpException, xxx, xxx)
    // 支持的内置异常列表文档:https://docs.nestjs.cn/10/exceptionfilters?id=%e5%86%85%e7%bd%aehttp%e5%bc%82%e5%b8%b8
    @Catch(HttpException)
    export class HttpExceptionFilter<T> implements ExceptionFilter {
      // exception:当前正在处理的异常对象
      // host:传递给原始处理程序的一个包装(Response/Request)引用参数
      catch(exception: HttpException, host: ArgumentsHost) {
        // 获取上下文
        const ctx = host.switchToHttp();
        // 响应对象,跟接口中 @Response @Res 取到的一样
        const response = ctx.getResponse<Response>();
        // 请求对象,跟接口中 @Request @Req 取到的一样
        const request = ctx.getRequest<Request>();
        // 异常状态
        const status = exception.getStatus();
        // 抛出错误日志
        response
          .status(status)
          .json({
            dzm: '测试字段',
            statusCode: status,
            timestamp: new Date().toISOString(),
            path: request.url
          });
      }
    }
    

二、局部支持异常处理

image.png

  • 某个接口

    import { Controller, Get, Body, Query, Post, Param, Request, Req, Res, Redirect, HttpCode, HttpException, HttpStatus, UseFilters } from '@nestjs/common';
    import { UserService } from './user.service';
    // 这里也需要引入
    import { HttpExceptionFilter } from 'src/http-exception.filter';
    
    @Controller('user')
    export class UserController {
      constructor(private readonly userService: UserService) { }
    
      @Get('/dzm')
      // 添加上过滤器
      @UseFilters(new HttpExceptionFilter())
      getDzm(@Req() req: any, @Res() res: any): any {
        // 故意抛出异常进行测试
        throw new HttpException('Forbidden', HttpStatus.FORBIDDEN)
        res.send(req.query)
      }
    }
    
  • 某个控制器下的所有接口

    import { Controller, Get, Body, Query, Post, Param, Request, Req, Res, Redirect, HttpCode, HttpException, HttpStatus, UseFilters } from '@nestjs/common';
    import { UserService } from './user.service';
    import { HttpExceptionFilter } from 'src/http-exception.filter';
    
    @Controller('user')
    @UseFilters(new HttpExceptionFilter())
    export class UserController {
      constructor(private readonly userService: UserService) { }
    
      @Get('/dzm')
      getDzm(@Req() req: any, @Res() res: any): any {
        // 故意抛出异常进行测试
        throw new HttpException('Forbidden', HttpStatus.FORBIDDEN)
        res.send(req.query)
      }
    }
    

三、全局异常处理

  • 方式一:main.ts,无法注入依赖

    import { NestFactory } from '@nestjs/core';
    import { AppModule } from './app.module';
    import { HttpExceptionFilter } from './http-exception.filter';
    
    async function bootstrap() {
      const app = await NestFactory.create(AppModule);
      // 全局注册异常过滤器
      app.useGlobalFilters(new HttpExceptionFilter())
      await app.listen(3000);
    }
    bootstrap();
    
  • 方式二:app.module.ts,支持注入依赖

    import { Module } from '@nestjs/common';
    import { AppController } from './app.controller';
    import { AppService } from './app.service';
    import { UserModule } from './user/user.module';
    import { LoginModule } from './login/login.module';
    import { APP_FILTER } from '@nestjs/core';
    import { HttpExceptionFilter } from './http-exception.filter';
    
    @Module({
      imports: [UserModule, LoginModule],
      controllers: [AppController],
      providers: [
        AppService,
        // 这样注册即可,效果一样,可以根据需要使用此技术添加任意数量的过滤器
        {
          provide: APP_FILTER,
          useClass: HttpExceptionFilter,
        },
      ],
    })
    export class AppModule { }