Nest grpc 实践之调用 python ddddocr 库

文章介绍了如何通过gRPC和protobuf在Nest.js中调用ddddocr库以优化性能,对比了HTTP和Websocket的不足,并详细展示了配置Nest的gRPC微服务,使用Postman调试gRPC服务,以及protobuf消息编码的过程。最后,给出了Nest客户端和服务端Python实现的示例代码。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

我曾经写过一个项目 ddddocr_server,使用 fastapi 提供 http 接口,以此来调用 ddddocr 库。

其他语言想要调用的话,则是通过 http 协议的方式来调用。然而 http 协议的开销不小,而 Websocket 调用又不灵活,此时针对这种应用场景的最佳选择就是 rpc(Remote Procedure Call 远程过程调用),而这次所要用的技术便是 grpc。

早闻 gRPC 大名,所以这次将使用 nest 通过 grpc 的方式来调用 ddddocr 库来识别验证码。

效果图

Untitled

本文源码 nest-ocr

简单熟悉下 grpc

由于我们的调用方是 nest,因此就很有必要熟悉一下 nest 要如何创建

官方提供了一个 样例,本文便在此基础上进行更改。

首先,在 nest 中 grpc 是以微服务的方式启动的,从代码上也就 3 行便可实现。

const app = await NestFactory.create(AppModule)

app.connectMicroservice <
  MicroserviceOptions >
  {
    transport: Transport.GRPC,
    options: {
      package: 'hero',
      protoPath: join(__dirname, './hero/hero.proto'),
    },
  }

await app.startAllMicroservices()

既然服务有了,那么要如何调用呢?或者说有没有像 http 接口调试工具能够调用 grpc 服务,有很多种 grpc 客户端工具,但这里选择 Postman。

Untitled

创建 API

不过这里先别急着调用,为了后续调试,建议先到工作区的 APIs 中添加一个 API,然后将样例中的 hero.proto 中导入进来

Untitled

导入完毕后将显示如下页面

Untitled

创建 gRPC 客户端

点击工作区旁边的 New 按钮(不是 + 按钮),选择 gRPC

Untitled

在 Enter URL 输入框填写 localhost:5000 (nest grpc 默认地址),这里你也可以选择第一个官方的 gRPC 测试服务,用于看看效果。

Untitled

填写完毕后,你会发现在右侧 Select a method 中并没有看到所定义的两个方法:FindOne,FindMang,这时候我们需要将 hero.proto 文件导入进来,如果你完成了 创建 API 那一步骤,你在右侧便能看到那两个方法

Untitled

此时不妨选择一下 FindOne,然后点击下方 Use Example Message,将 id 填为 1,点击 Invoke,得到的效果图如下。

Untitled

到这里我们就已经搞定了如何调用 grpc 服务,接下来就要自己去实现标题的需求。

Protobuf 消息编码

在 grpc 中,数据传输部分通过 Protobuf(Protocol Buffers)定义

因为从上面服务调用来看,貌似与 http 协议调用不相上下。

其实不然,protobuf 不同于 JSON、XML 数据,是以二进制数据流传输,数据在经 protobuf 序列化后的消息体积很小(传输内容少,传输相对就快)。同时在加上 HTTP/2 协议的加持(底层传输协议,可替换为其他协议),使得 gRPC 的传输性能要优于传统 Restful。

protobuf 对于数据传输的优点有很多,如 **支持流式传输,不过这就不是本文所述的内容了。总之你只要知道 grpc 性能高的原因就是因为 protobuf。**

首先来看 hero.proto 这个文件的内容

syntax = "proto3";

package hero;

service HeroService {
  rpc FindOne (HeroById) returns (Hero);
  rpc FindMany (stream HeroById) returns (stream Hero);
}

message HeroById {
  int32 id = 1;
}

message Hero {
  int32 id = 1;
  string name = 2;
}

不难看出,package 定义包名,service 定义服务,而 message 则是定义数据传输的类型。

客户端与服务端将根据 protobuf 来生成双方交互方式,其中包名决定了双方传输的作用域,service 下的函数就是双方之间的预先定义好要以什么样的数据发送,又以什么样的数据返回。

我个人是觉得没什么特别重点的部分,根据自己的需求然后修改基本数据结构便可。

实践

首先,要明确谁是客户端,谁是服务端。

从 标题 上来看,不难看出是 js(client) ⇒ python(server),也就是 nest 调用 ddddocr 这个库,那么 nest 就应该作为客户端,而 python 作为服务端。

先将整个流程先捋一遍,如图下图示意。

Untitled

用户想要调用 ddddocr 库,最理想的肯定是让用户直接和 python 打交道,但应用(这里指 Web)通常不会使用 python 进行编写,而其他语言(js)想要跨语言调用,这时 rpc 就再适合不过了。

可能会有人说这么操作多此一举,我只能说根据性能和业务为主。相比将 nest 后端服务迁移到 python 上,和在 nest 与 python 之间多层 grpc,在两者的工作量之下我肯定毫不疑问的选择后者。

protobuf 定义

syntax = "proto3";

package ocr;

service OCR {
  rpc Character (Chara
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值