如何在Nest.js中全局复用统一的错误处理逻辑?
Nest.js 复用错误处理逻辑方案
我已经按项目要求实现了错误处理逻辑,但不想在每个控制器路由里重复编写相同的try/catch代码,示例场景如下:
@Controller() export class AppController { constructor(private readonly appService: AppService) {} @Get('test/:returnError') async test(@Param() param: { returnError: string }) { try { const shouldThrow = String(param.returnError).toLowerCase() === 'true'; await this.appService.example(shouldThrow); if (shouldThrow) throw new ErrorResponse(401, 'error test', { b: 1 }); return new SuccessResponse('ok', { test: '1' }); } catch (error: unknown) { if (error instanceof ErrorResponse) return error; throw new InternalServerErrorException(error); } } }
需要复用的核心逻辑是:
try { ...业务逻辑 } catch (error: unknown) { if (error instanceof ErrorResponse) return error; throw new InternalServerErrorException(error); }
下面提供几种可行的实现方案:
方案一:自定义拦截器+装饰器
通过Nest的拦截器机制,统一处理路由执行中的错误:
首先定义拦截器:
import { ExecutionContext, CallHandler, NestInterceptor } from '@nestjs/common'; import { Observable, catchError } from 'rxjs'; import { InternalServerErrorException } from '@nestjs/common'; export class ErrorHandlingInterceptor implements NestInterceptor { intercept(context: ExecutionContext, next: CallHandler): Observable<any> { return next.handle().pipe( catchError(error => { if (error instanceof ErrorResponse) { throw error; // Nest会自动识别并返回自定义错误响应 } throw new InternalServerErrorException(error); }), ); } }
再封装成方便使用的装饰器:
import { UseInterceptors } from '@nestjs/common'; import { ErrorHandlingInterceptor } from './error-handling.interceptor'; export const HandleErrors = () => UseInterceptors(ErrorHandlingInterceptor);
使用时直接在控制器或路由上添加装饰器:
@Controller() @HandleErrors() // 该控制器下所有路由自动应用错误处理 export class AppController { constructor(private readonly appService: AppService) {} @Get('test/:returnError') async test(@Param() param: { returnError: string }) { const shouldThrow = String(param.returnError).toLowerCase() === 'true'; await this.appService.example(shouldThrow); if (shouldThrow) throw new ErrorResponse(401, 'error test', { b: 1 }); return new SuccessResponse('ok', { test: '1' }); // 无需再写try/catch } }
方案二:全局拦截器
如果要让整个项目的所有路由都自动应用该错误处理逻辑,直接在根模块注册全局拦截器:
import { Module } from '@nestjs/common'; import { APP_INTERCEPTOR } from '@nestjs/core'; import { ErrorHandlingInterceptor } from './error-handling.interceptor'; @Module({ providers: [ { provide: APP_INTERCEPTOR, useClass: ErrorHandlingInterceptor, }, ], }) export class AppModule {}
这样所有路由的错误都会被统一处理,无需逐个添加装饰器。
方案三:工具函数封装
如果不想用拦截器,也可以写一个工具函数来包裹业务逻辑:
import { InternalServerErrorException } from '@nestjs/common'; export async function handleError<T>(fn: () => Promise<T>): Promise<T> { try { return await fn(); } catch (error: unknown) { if (error instanceof ErrorResponse) { throw error; } throw new InternalServerErrorException(error); } }
在路由中使用:
@Get('test/:returnError') async test(@Param() param: { returnError: string }) { return handleError(async () => { const shouldThrow = String(param.returnError).toLowerCase() === 'true'; await this.appService.example(shouldThrow); if (shouldThrow) throw new ErrorResponse(401, 'error test', { b: 1 }); return new SuccessResponse('ok', { test: '1' }); }); }
内容的提问来源于stack exchange,提问作者Andronik Nazaryan
相关产品推荐
相关产品推荐

