Skip to content

NestJS 异常过滤器绑定方式

NestJS 支持局部注册和全局注册两种方式,优先级:局部 > 全局。

局部绑定

局部又分为控制器级和路由级,控制器级别:作用于控制器所有路由,路由级别:仅作用于单个路由

通过 @UseFilters 装饰器注册,仅对当前控制器 / 方法生效:

ts
// src/controllers/user.controller.ts
import { Controller, Get, UseFilters } from '@nestjs/common';
import { HttpExceptionFilter } from '../filters/http-exception.filter';

// 控制器级别:所有方法生效
@Controller('users')
@UseFilters(HttpExceptionFilter)
export class UserController {
  // 方法级别:仅该方法生效(优先级高于控制器)
  @Get()
  @UseFilters(HttpExceptionFilter)
  findAll() {
    throw new HttpException('自定义异常', HttpStatus.BAD_REQUEST);
  }
}

全局绑定

全局注册后,所有未被局部过滤器处理的异常都会被捕获:

  1. 方式一:通过 providers 注册(推荐,支持依赖注入)
ts
// src/app.module.ts
import { Module } from '@nestjs/common';
import { APP_INTERCEPTOR } from '@nestjs/core';
import { LoggerExceptionFilter } from './filters/logger-exception.filter';
import { LoggerService } from './services/logger.service';

@Module({
  providers: [
    LoggerService,
    {
      provide: APP_INTERCEPTOR,
      useClass: LoggerExceptionFilter, // 全局生效
    },
  ],
})
export class AppModule {}
  1. 方式二:通过 NestFactory 注册(不支持依赖注入)
ts
// src/main.ts
import { NestFactory } from '@nestjs/core';
import { AppModule } from './app.module';
import { HttpExceptionFilter } from './filters/http-exception.filter';

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

  // 全局注册(方式1:直接传入实例)
  app.useGlobalFilters(new HttpExceptionFilter());

  await app.listen(3000);
}
bootstrap();
  1. 拓展: 捕获所有异常

若需捕获所有类型异常(包括 HttpException、普通 Error、自定义异常),只需将 @Catch() 装饰器留空:

ts
@Catch() // 无参数 = 捕获所有异常
export class AllExceptionsFilter implements ExceptionFilter {
  catch(exception: unknown, host: ArgumentsHost) {
    const ctx = host.switchToHttp();
    const response = ctx.getResponse<Response>();
    const request = ctx.getRequest<Request>();

    // 区分 HttpException 和普通异常
    const status = exception instanceof HttpException
      ? exception.getStatus()
      : HttpStatus.INTERNAL_SERVER_ERROR;

    const message = exception instanceof HttpException
      ? exception.getResponse()
      : (exception as Error).message || 'Internal server error';

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

动态绑定(基于条件)

通过自定义装饰器或逻辑动态决定是否应用异常过滤器

ts
// 自定义装饰器:仅对生产环境应用日志异常过滤器
export const UseProdLogger = () => {
  return process.env.NODE_ENV === 'production' ? UseInterceptors(LoggerInterceptor) : () => {};
};

// 使用
@Controller('orders')
@UseProdLogger()
export class OrdersController {}