如何在 NestJS 中处理 RpcException

2023-11-29

我正在尝试构建一个包含多个微服务的 NestJS 后端和一个作为与微服务通信的网关的 REST API。对于网关和微服务之间的通信,我使用 gRPC。 简单的通信已经可以工作,但现在我想在微服务中实现错误处理。 NestJS 文档指出,这可以通过 RpcException 类实现。https://docs.nestjs.com/microservices/exception-filters但是,如果我尝试捕获网关 API 中的异常,我只会收到“ERROR [ExceptionsHandler] 2 UNKNOWN: ...”,后面跟着异常错误消息。

网关API: 用户控制器.ts

import { Controller, Get, Param } from '@nestjs/common';
import { ApiTags } from '@nestjs/swagger';
import { UserViewModel } from '../../proto/build/service-name/user';
import { UserService } from './user.service';

@Controller('user')
export class UserController {
  constructor(private readonly userService: UserService) {}

  @Get(':id')
  async getUserById(@Param('id') id: number): Promise<UserViewModel> {
    try {
      return await this.userService.getUserById(id);
    } catch (error) {
      return error;
    }
  }
}

网关API: 用户服务.ts

import { Inject, Injectable, OnModuleInit } from '@nestjs/common';
import { ClientGrpc } from '@nestjs/microservices';
import {
  IUserService,
  UserViewModel,
} from '../../proto/build/service-name/user';

@Injectable()
export class UserService implements OnModuleInit {
  private grpcService: IUserService;

  constructor(@Inject('USER_PACKAGE') private client: ClientGrpc) {}

  onModuleInit() {
    this.grpcService = this.client.getService<IUserService>('IUserService');
  }

  async getUserById(id: number): Promise<UserViewModel> {
    return this.grpcService.getUserById({ id });
  }
}

微服务: 用户控制器.ts

import { Metadata } from '@grpc/grpc-js';
import { Controller } from '@nestjs/common';
import { GrpcMethod, RpcException } from '@nestjs/microservices';
import { User } from './../../node_modules/.prisma/client/index.d';
import { PrismaService } from '../prisma/prisma.service';
import { UserViewModel, GetUserById } from '../proto/build/service-name/user';

@Controller()
export class UserController {
  constructor(private readonly prisma: PrismaService) {}

  @GrpcMethod('IUserService', 'getUserById')
  async getUserById(
    data: GetUserById,
    metadata: Metadata,
  ): Promise<UserViewModel> {
    const user: User = await this.prisma.user.findFirst({
      where: { id: { equals: data.id } },
    });

    if (!user) {
      throw new RpcException('User not found');
    }

    return { name: user.name, email: user.email };
  }
}


我在使用 API 网关构建微服务时也遇到了这个问题。我提出的解决方案是我在这里找到的答案的组合,但允许您使用 NestJS 异常中的构建。

所以基本上我用以下内容包装了内置的 NestJS HTTP 异常RpcException在微服务中。然后,您可以在 api 网关中捕获异常并使用过滤器进行处理。这RcpException消息可以是string or object,这允许您传递内置的 HTTP 异常(NotFoundException, UnauthorizedException等)作为消息,这样您就不必处理状态代码。

微服务

// Some service method to fetch a product by id
public async findById(id: number): Promise<Product> {
  // ...
  if (!product) {
    throw new RpcException(
      new NotFoundException("Product was not found!");
    );
  }
  //...
}

网关控制器

@Get(':productId')
public getProductById(@Param('productId') productId: number): Observable<any> {
  return this._productsServiceClient
    .send({ cmd: 'find-by-id' }, { productId })
    .pipe(catchError(error => throwError(() => new RpcException(error.response))))
}

异常过滤器

import { ArgumentsHost, Catch, ExceptionFilter } from '@nestjs/common';
import { RpcException } from '@nestjs/microservices';
import { Response } from 'express';

@Catch(RpcException)
export class RpcExceptionFilter implements ExceptionFilter {
  catch(exception: RpcException, host: ArgumentsHost) {
    const error: any = exception.getError();
    const ctx = host.switchToHttp();
    const response = ctx.getResponse<Response>();
    
    response
      .status(error.statusCode)
      .json(error);
  }
}

注册过滤器

// main.ts
app.useGlobalFilters(new RpcExceptionFilter());
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

如何在 NestJS 中处理 RpcException 的相关文章

随机推荐

  • 如何在不使用“占位符” while 条件的情况下安全地循环,直到没有更多事情可做?

    为了调用我的 Web API 方法 直到没有更多数据返回 由于客户端 Windows CE 手持设备 的 98 磅弱角色 我分批获取它 以保持每个结果集较小 我正在使用这段代码 while moreRecordsExist redempti
  • 在CKFinder中自定义baseUrl和baseDir

    我们在许多 CMS 应用程序中使用 CKEditor 和 CKFinder for Coldfusion 这些应用程序指向我们服务器上的不同站点 因此我们希望 CKFinder 设置将文件上传到每个应用程序的特定目录 但我们希望服务器上的
  • 如何从数学角度看待高阶函数和IO动作?

    我试图从第一原理来理解函数式编程 但我却陷入了纯函数世界和具有状态和副作用的不纯现实世界之间的界面 从数学的角度来看 什么是返回函数的函数 什么是返回 IO 操作的函数 如 Haskell 的 IO 类型 详细说明 根据我的理解 纯函数是从
  • 关于mvc:intercepter,如何设置排除路径

    众所周知 我们可以这样配置拦截器
  • 更改android复选框的大小

    在我的 Android 应用程序中 我需要更改 Android 复选框的大小 我搜索并了解到它不能通过简单地更改属性来完成 我找到了这个链接但无法真正弄清楚到底需要做什么 找不到此链接 android sdk windows 1 0 r2
  • 使用主动/被动冗余模型的应用程序应如何使用 Kubernetes 进行容器化?

    我有一个在虚拟机上运行的分布式应用程序 其中有一个以主动 被动模式运行的服务 主用虚拟机通过公网IP提供服务 如果主动虚拟机发生故障 公共 IP 将移至被动虚拟机 被动虚拟机将变为主动虚拟机并开始提供服务 这种模式如何适合 kubernet
  • 在网页中显示 PDF

    我正在使用 Spring MVC 我想将 PDF 文件从本地显示到网页 我不知道我应该对我的控制器做什么来做到这一点 我看到一些类似的问题 其答案返回ResponseEntity
  • R:对 2 个数据帧的行进行 t 测试

    我有两个数据框 我想对行进行独立的 2 组 t 检验 即t test y1 y2 where y1是 dataframe1 中的一行并且y2与数据帧2中的匹配行 实现这一目标的最佳方法是什么 编辑 我刚刚找到了格式 dataframe1 i
  • 如何隐藏iOS状态下录音时的红条?

    我使用AVAudioRecorder来录制语音 我发现有时当我分配它并开始录音时 状态栏下会出现一个红色条 就像您在后台调用时的红色条 如何隐藏它 你不能那样做 每个应用程序 包括内置的语音备忘录应用程序 在使用麦克风时都会有该栏
  • 通过 JAXB 解组读取自定义 XML 处理指令

    通过 JAXB 解组时有没有办法读取自定义 xml 处理指令 例子
  • 更快的 UIImage - Base64 转换

    我正在做的工作必须在之间进行编码和解码UIImage和 Base 64 字符串 这对于较小的图像非常有效 向前和向后转换只需不到 1 秒 但当我将其应用于较大的图像时 需要很长时间 几乎一分钟 有没有其他方法来编码和解码UIImage对象字
  • 调用 ffmpeg.c 的 main 两次导致应用程序崩溃

    使用 FFmpeg 4 0 2 并调用它ffmpeg c s main函数两次导致 Android 应用程序崩溃 使用 FFmpeg 共享库和 JNI A libc Fatal signal 11 SIGSEGV code 1 fault
  • 使用通用参数作为端口数组长度

    我想做的事 entity FIRfilter is generic NTAPS integer port h in array 0 to NTAPS 1 of std logic vector 15 downto 0 end FIRfitl
  • 基于数据库数组PHP自动检查复选框

    在我的页面的 用户设置 选项卡中 我希望用户确定特定用户发布的帖子类型 表格如下
  • Spark独立模式和本地模式有什么区别?

    Spark独立模式和本地模式有什么区别 Spark Standalone是一个可以在集群上工作的资源管理器 它只是内置的资源管理器 而不是像纱线这样的外部资源管理器 Spark本地运行无需任何资源管理器 一切都在单个jvm中运行 您可以决定
  • Java 同步方法...不同步

    对于我当前的 java 练习 我必须从 2 个不同的 Gmail 帐户获取邮件 我通过创建 Gmail 类的新实例来完成此操作 gmail 类扩展了线程 其中有一个同步方法 readMail 用于获取邮件并打印它 这个 readMail 方
  • 使用 NLog 将记录器名称写入 Excel 文件

    感谢 Rolf 在这个问题中的评论 NLog 在 C 中具有严重性和类别 我能够将日志消息的类别 例如 热 或 数据库 或 机械 记录到文本文件中 我只需将名称传递给 GetLogger 方法即可完成此操作 public MainWindo
  • Mongoimport 带有字符串 _id 和 upsert 的 csv 文件

    我正在尝试使用 mongoimport 来更新插入 id 中带有字符串值的数据 由于 id 看起来像整数 即使它们在引号中 因此 mongoimport 将它们视为整数并创建新记录 而不是更新插入现有记录 我正在运行的命令 mongoimp
  • Android GPU 分析 - OpenGL 动态壁纸速度很慢

    我正在使用 OpenGL ES 3 0 开发动态壁纸 我已经根据优秀教程进行了设置http www learnopengles com how to use opengl es 2 in an android live wallpaper
  • 如何在 NestJS 中处理 RpcException

    我正在尝试构建一个包含多个微服务的 NestJS 后端和一个作为与微服务通信的网关的 REST API 对于网关和微服务之间的通信 我使用 gRPC 简单的通信已经可以工作 但现在我想在微服务中实现错误处理 NestJS 文档指出 这可以通