NestJS ExceptionFilter能否实现类似Spring Boot @RestControllerAdvice的多错误全局处理?
NestJS 实现类似 Spring Boot @RestControllerAdvice 的全局多异常处理
你完全没写错基础用法,但NestJS的ExceptionFilter其实有更灵活的姿势,完全能实现和Spring @RestControllerAdvice一样的多异常处理能力,甚至能覆盖包括非HttpException在内的所有全局错误。下面给你拆解两种核心实现方式:
1. 精准捕获指定的多种异常类型
和Spring里多个@ExceptionHandler对应,你可以给@Catch()装饰器传入多个异常类,这样一个Filter就能针对性处理不同的异常场景:
import { Catch, ExceptionFilter, ArgumentsHost, HttpStatus } from '@nestjs/common'; import { HttpException, Logger } from '@nestjs/common'; import { Response, Request } from 'express'; // 导入你的自定义异常 import { DuplicateEmailException } from './exceptions/duplicate-email.exception'; import { MethodArgumentNotValidException } from './exceptions/validation.exception'; @Catch(HttpException, DuplicateEmailException, MethodArgumentNotValidException) export class GlobalExceptionHandler implements ExceptionFilter { private readonly logger = new Logger(GlobalExceptionHandler.name); catch(exception: unknown, host: ArgumentsHost) { const ctx = host.switchToHttp(); const response = ctx.getResponse<Response>(); const request = ctx.getRequest<Request>(); // 处理自定义重复邮箱异常 if (exception instanceof DuplicateEmailException) { this.logger.error(`Duplicate email error: ${exception.message}, Path: ${request.url}`); response.status(HttpStatus.BAD_REQUEST).json({ statusCode: HttpStatus.BAD_REQUEST, message: '该邮箱已被注册', path: request.url, timestamp: new Date().toISOString() }); return; } // 处理参数校验异常 if (exception instanceof MethodArgumentNotValidException) { const validationErrors = exception.getValidationErrors(); this.logger.error(`Validation error: ${JSON.stringify(validationErrors)}, Path: ${request.url}`); response.status(HttpStatus.BAD_REQUEST).json({ statusCode: HttpStatus.BAD_REQUEST, message: '参数格式错误', details: validationErrors.map(err => ({ field: err.property, message: err.constraints })), path: request.url, timestamp: new Date().toISOString() }); return; } // 处理所有HttpException子类 if (exception instanceof HttpException) { const status = exception.getStatus(); this.logger.error(`HttpException: ${exception.message}, Path: ${request.url}`); response.status(status).json({ statusCode: status, message: exception.message, path: request.url, timestamp: new Date().toISOString() }); return; } } }
2. 捕获全局所有异常(包括非HttpException)
如果想覆盖所有未被捕获的错误(比如代码里的TypeError、普通Error),只需要给@Catch()不传任何参数,然后在catch方法里做类型判断即可:
import { Catch, ExceptionFilter, ArgumentsHost, HttpStatus } from '@nestjs/common'; import { Logger } from '@nestjs/common'; import { Response, Request } from 'express'; @Catch() export class GlobalExceptionHandler implements ExceptionFilter { private readonly logger = new Logger(GlobalExceptionHandler.name); catch(exception: unknown, host: ArgumentsHost) { const ctx = host.switchToHttp(); const response = ctx.getResponse<Response>(); const request = ctx.getRequest<Request>(); // 优先处理已知的异常类型 if (exception instanceof HttpException) { const status = exception.getStatus(); this.logger.error(`HttpException: ${exception.message}, Path: ${request.url}`); response.status(status).json({ statusCode: status, message: exception.message, path: request.url, timestamp: new Date().toISOString() }); return; } // 处理自定义非Http异常 if ((exception as any).name === 'DuplicateEmailException') { this.logger.error(`Duplicate email error: ${(exception as Error).message}, Path: ${request.url}`); response.status(HttpStatus.BAD_REQUEST).json({ statusCode: HttpStatus.BAD_REQUEST, message: '该邮箱已被注册', path: request.url, timestamp: new Date().toISOString() }); return; } // 兜底处理所有未知错误 this.logger.error(`Unexpected error: ${(exception as Error).message}\nStack: ${(exception as Error).stack}`); response.status(HttpStatus.INTERNAL_SERVER_ERROR).json({ statusCode: HttpStatus.INTERNAL_SERVER_ERROR, message: '服务器内部错误', path: request.url, timestamp: new Date().toISOString() }); } }
最后:注册全局Filter
不管用哪种方式,都需要在main.ts里把Filter注册为全局生效:
import { NestFactory } from '@nestjs/core'; import { AppModule } from './app.module'; import { GlobalExceptionHandler } from './exception-handler.filter'; async function bootstrap() { const app = await NestFactory.create(AppModule); // 注册全局异常过滤器 app.useGlobalFilters(new GlobalExceptionHandler()); await app.listen(3000); } bootstrap();
这样一来,你的NestJS应用就拥有了和Spring @RestControllerAdvice几乎一致的全局异常处理能力,既能精准处理特定异常,也能兜底所有未知错误。
内容的提问来源于stack exchange,提问作者momo
相关产品推荐
相关产品推荐

