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

NestJS微服务跨服务RPC异常转HTTP异常处理问题

NestJS微服务跨服务异常处理解决方案

一、确保Service-A的异常正确序列化

Service-A抛出的异常必须属于NestJS RPC体系可识别的类型,需继承RpcException并携带结构化错误信息:

// service-a/src/exceptions/my-rpc.exception.ts
import { RpcException } from '@nestjs/microservices';

export class MyRpcException extends RpcException {
  constructor(message: string, statusCode: number) {
    super({
      message,
      statusCode,
    });
  }
}

在CommandHandler中按业务逻辑抛出:

// service-a/src/commands/handlers/xxx.handler.ts
import { CommandHandler, ICommandHandler } from '@nestjs/cqrs';
import { MyRpcException } from '../../exceptions/my-rpc.exception';

@CommandHandler(YourCommand)
export class YourCommandHandler implements ICommandHandler<YourCommand> {
  async execute(command: YourCommand) {
    if (errorCondition) {
      throw new MyRpcException('操作执行失败', 500);
    }
    // 正常业务逻辑
  }
}

二、API网关层捕获RPC异常并转为HTTP响应

针对网关的REST→RabbitMQ RPC调用流程,提供两种可靠处理方式:

方式1:服务层手动捕获转换

在网关调用RPC的Service中,用try/catch包裹调用逻辑,将RpcException转为HTTPException:

// api-gateway/src/services/xxx.service.ts
import { Injectable, HttpException, HttpStatus } from '@nestjs/common';
import { ClientProxy, RpcException } from '@nestjs/microservices';
import { Inject } from '@nestjs/common';

@Injectable()
export class XxxService {
  constructor(@Inject('SERVICE_A_CLIENT') private readonly serviceAClient: ClientProxy) {}

  async callServiceA(data: any) {
    try {
      return await this.serviceAClient.send('your_rpc_pattern', data).toPromise();
    } catch (error) {
      if (error instanceof RpcException) {
        const errorData = error.getError();
        throw new HttpException(
          errorData.message,
          errorData.statusCode || HttpStatus.INTERNAL_SERVER_ERROR,
        );
      }
      throw new HttpException('服务调用失败', HttpStatus.INTERNAL_SERVER_ERROR);
    }
  }
}

方式2:全局过滤器统一处理

创建全局异常过滤器,自动识别RpcException并转换为标准HTTP响应:

// api-gateway/src/filters/rpc-exception.filter.ts
import { ExceptionFilter, Catch, ArgumentsHost, HttpException, HttpStatus } from '@nestjs/common';
import { RpcException } from '@nestjs/microservices';

@Catch(RpcException)
export class RpcExceptionFilter implements ExceptionFilter {
  catch(exception: RpcException, host: ArgumentsHost) {
    const ctx = host.switchToHttp();
    const response = ctx.getResponse();
    const request = ctx.getRequest();

    const errorData = exception.getError();
    const status = typeof errorData === 'object' && errorData.statusCode 
      ? errorData.statusCode 
      : HttpStatus.INTERNAL_SERVER_ERROR;
    const message = typeof errorData === 'object' && errorData.message 
      ? errorData.message 
      : '服务异常';

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

在网关main.ts中注册全局过滤器:

// api-gateway/src/main.ts
import { NestFactory } from '@nestjs/core';
import { AppModule } from './app.module';
import { RpcExceptionFilter } from './filters/rpc-exception.filter';

async function bootstrap() {
  const app = await NestFactory.create(AppModule);
  app.useGlobalFilters(new RpcExceptionFilter());
  await app.listen(3000);
}
bootstrap();

三、排查常见失效场景

  • 确认网关RPC客户端配置正确,调用send方法后需调用toPromise()(Observable需正确订阅并处理错误)
  • 检查Service-A的微服务启动代码,未自定义异常过滤器覆盖默认RPC异常处理逻辑
  • 验证网关Controller的响应配置:若接口用@Post()且未手动指定状态码,未捕获异常时会默认返回201,需确保异常被正确抛出到Controller层

内容的提问来源于stack exchange,提问作者DavidSch

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.10 06:05:21