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
相关产品推荐
相关产品推荐

