Nest HttpExceptionFilter异常过滤器 拦截器 中间件

异常过滤器

@UseFilters

@UseFilters 用于设置异常过滤器,作用于控制器 MethodDecorator & ClassDecorator:

import { Controller, UseFilters } from '@nestjs/common';

@Controller('user')
@UseFilters(MyHttpExceptionFilter, OtherFilter)
export class UserController {
  @Get()
  @UseFilters(MyHttpExceptionFilter, OtherFilter)
  async fn() {}
  ...
}

如果需要全局过滤器:

import { NestFactory } from '@nestjs/core';
import { NestExpressApplication } from '@nestjs/platform-express';
import { ConfigService } from '@nestjs/config';
import { AppModule } from './app.module';
import { text } from 'body-parser';
import * as xmlparser from 'express-xml-bodyparser';
import * as cookieParser from 'cookie-parser';
import { join } from 'path';
import { GlobalExceptionFilter } from './common/filter/global.filter';

async function bootstrap() {
  const app = await NestFactory.create<NestExpressApplication>(AppModule);
  app.enableCors();
  app.use(cookieParser());
  app.use(text());
  app.use(xmlparser());
  app.useStaticAssets(join(process.cwd(), 'public'));
  app.useGlobalFilters(new GlobalExceptionFilter());      // 设置全局异常过滤器
  const configService = app.get(ConfigService);
  process.title = configService.get<string>('TITLE');

  const PORT = configService.get<number>('PORT');
  await app.listen(PORT);

  console.log(`server running at port:${PORT}`);
}
bootstrap();

这种情况下,过滤器不能使用依赖注入,怎么办呢?只能手动获取了:

async function bootstrap() {
  const app = await NestFactory.create<NestExpressApplication>(AppModule);

  const configService = app.get(ConfigService);
  app.useGlobalFilters(new GlobalExceptionFilter(configService));
  process.title = configService.get<string>('TITLE');
}

BaseExceptionFilter

import { ExceptionFilter, Catch, ArgumentsHost, HttpException, HttpStatus } from '@nestjs/common';
import { BaseExceptionFilter } from '@nestjs/core';
import { Request, Response } from 'express';

@Catch(Error)
export class GlobalExceptionFilter extends BaseExceptionFilter implements ExceptionFilter {

  catch(exception: unknown, host: ArgumentsHost) {
    if (exception instanceof HttpException) {
        return this.catchHttpException(exception, host);
    }
    if (exception instanceof Error) {
        return this.catchError(exception, host);
    }
    // return super.catch(exception, host) // 使用 @Catch() 捕获全部抛出可能运行到此,但是如果不注入 HttpAdapterHost 依赖则 BaseExceptionFilter 会抛异常
  }

  catchError(exception: Error, host: ArgumentsHost) {
    const ctx = host.switchToHttp();
    const response = ctx.getResponse<Response>();
    
    response
      .status(HttpStatus.BAD_GATEWAY)
      .json({
        error: 'ERROR!'
      })
  }

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

}

全局过滤器可以继承基本过滤器,需要手动注入 HttpAdapterHost 依赖:

async function bootstrap() {
  const app = await NestFactory.create(AppModule);

  const { httpAdapter } = app.get(HttpAdapterHost);
  app.useGlobalFilters(new AllExceptionsFilter(httpAdapter));

  await app.listen(3000);
}
bootstrap();

注意

异常过滤器只能捕获控制器内抛出的异常,不能捕获拦截器和中间件抛出的异常,这些异常会导致整个应用程序停止运行,因此要小心使用。
通常,对于 Observable 进行 pipe 或者 subscribe 操作时,需要处理好 catchError操作 和 error(e) 回调。

拦截器

@UseInterceptors

@UseInterceptors 用于设置拦截器,作用于控制器 MethodDecorator & ClassDecorator:

import { Controller, UseInterceptors } from '@nestjs/common';

@Controller('user')
@UseFilters(A, B)
export class UserController {
  @Get()
  @UseInterceptors(C)
  async fn() {}
  ...
}

也可以设置全局拦截器:

app.useGlobalInterceptors(A, B, C);

中间件

posted @ 2023-05-26 10:24  develon  阅读(174)  评论(0编辑  收藏  举报