You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.05 09:15:03