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);
}
}全局绑定
全局注册后,所有未被局部过滤器处理的异常都会被捕获:
- 方式一:通过 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 {}- 方式二:通过 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();- 拓展: 捕获所有异常
若需捕获所有类型异常(包括 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 {}