nest 异常过滤器

时间:2023-01-05 浏览:198 分类:NestJS

HTTP请求异常类

请求异常类可以直接向客户端抛出异常,并附带异常信息,和异常状态码。在nest.js 中是 HttpException 类封装的,最简单的可以在response中直接抛出,response的消息JSON分为两部分,分别是message 和statusCode。

  • message:基于状态的 HTTP 错误的简短描述

  • statusCode:默认为 status 参数中提供的 HTTP 状态代码

在nest中可以自定义为:

import {Injectable} from '@nestjs/common';
import {HttpException, HttpStatus} from "@nestjs/common";

@Injectable()
export class UserService {

    submit(body) {
        // 直接抛出forbidden异常,客户端会看到403 (Forbidden)
        throw new HttpException({
            status: HttpStatus.FORBIDDEN,
            message: 'This is a custom message',
        }, HttpStatus.FORBIDDEN);
    }
}

Nest 还提供了一组继承自基础 HttpException 的标准异常类。可以从 @nestjs/common 包中引用的,最常见的 HTTP 异常类有:

BadRequestException — 400
UnauthorizedException — 401
ForbiddenException — 403
NotFoundException — 404
MethodNotAllowedException - 405
NotAcceptableException — 406
RequestTimeoutException — 408
ConflictException — 409
GoneException — 410
PreconditionFailedException - 412
PayloadTooLargeException — 413
UnsupportedMediaTypeException — 415
ImATeapotException - 418
UnprocessableEntityException — 422
InternalServerErrorException — 500
NotImplementedException — 501
BadGatewayException — 502
ServiceUnavailableException — 503
GatewayTimeoutException — 504
HttpVersionNotSupportedException - 505

以上的异常类可以直接抛出,如:

import {Injectable} from '@nestjs/common';
import {MethodNotAllowedException  } from "@nestjs/common";

@Injectable()
export class UserService {

    submit(body) {
        //抛出 405异常
        throw new MethodNotAllowedException('这里是异常显示信息',{ cause: new Error(), description: '这里是说明'});
    }
}

定义异常过滤器

作用:用来抓取HttpException的异常,并且自定义返回response 的逻辑。使用Catch装饰器修饰,并且完善类下的catch() 方法:

// 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,
      });
  }
}

所有异常过滤器都应继承实现通用的 ExceptionFilter<T> 接口。这需要提供 catch(exception: T, host: ArgumentsHost) 具体方法及其指定的签名。 T 表示异常的类型。

如果不是通用标准HttpException,可以特定捕获相应的异常,比如页面未找到404异常,可以这么写:

// notfound-exception.filter.ts

import {Catch} from "@nestjs/common";   
import {NotFoundException, ExceptionFilter, ArgumentsHost} from "@nestjs/common";   
import { Request, Response } from 'express';
 
@Catch(NotFoundException)    
export class NotFoundExceptionFilter implements ExceptionFilter {    
    catch(exception: NotFoundException, host: ArgumentsHost) {  
    const ctx = host.switchToHttp();
    const response = ctx.getResponse<Response>();
    const request = ctx.getRequest<Request>();
    const status = exception.getStatus();
    // 渲染404页面
    response.render('404');    
    }    
}

绑定异常过滤器

  • 在控制器上引入 - UseFilters 装饰器:

@Post()
@UseFilters(new HttpExceptionFilter())
async create(@Body() createCatDto: CreateCatDto) {
  throw new ForbiddenException();
}
  • 全局引入 - 在app中引入 或者 在相应模块下引入:

// main.ts

async function bootstrap() {
  const app = await NestFactory.create(AppModule);
  // 方法一
  app.useGlobalFilters(new NotFoundExceptionFilter());
  await app.listen(3000);
}

bootstrap();
// app.module.ts

import { Module } from '@nestjs/common';
import { APP_FILTER } from '@nestjs/core';

@Module({
  // 方法二
  providers: [
    {
      provide: APP_FILTER,
      useClass: NotFoundExceptionFilter,
    },
  ],
})
export class AppModule {}