我曾经写过一个项目 ddddocr_server,使用 fastapi 提供 http 接口,以此来调用 ddddocr 库。
其他语言想要调用的话,则是通过 http 协议的方式来调用。然而 http 协议的开销不小,而 Websocket 调用又不灵活,此时针对这种应用场景的最佳选择就是 rpc(Remote Procedure Call 远程过程调用),而这次所要用的技术便是 grpc。
早闻 gRPC 大名,所以这次将使用 nest 通过 grpc 的方式来调用 python 的 ddddocr 库来识别验证码。
效果图
本文源码 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。
创建 API
不过这里先别急着调用,为了后续调试,建议先到工作区的 APIs 中添加一个 API,然后将样例中的 hero.proto 中导入进来
导入完毕后将显示如下页面
创建 gRPC 客户端
点击工作区旁边的 New 按钮(不是 + 按钮),选择 gRPC
在 Enter URL 输入框填写 localhost:5000 (nest grpc 默认地址),这里你也可以选择第一个官方的 gRPC 测试服务,用于看看效果。
填写完毕后,你会发现在右侧 Select a method 中并没有看到所定 义的两个方法:FindOne,FindMang,这时候我们需要将 hero.proto 文件导入进来,如果你完成了 创建 API 那一步骤,你在右侧便能看到那两个方法
此时不妨选择一下 FindOne,然后点击下方 Use Example Message,将 id 填为 1,点击 Invoke,得到的效果图如下。
到这里我们就已经搞定了如何调用 grpc 服务,接下来就要自己去实现标题的需求。
Protobuf 消息编码
在 grpc 中,数据传输部分通过 Protobuf(Protocol Buffers)定义
因为从上面服务调用来看,貌似与 http 协议调用不相上下。
其实不然,protobuf 不同于 JSON、XML 数据,是以二进制数据流传输,数据在经 protobuf 序列化后的消息体积很小(传输内容少,传输相对就快)。同时在加上 HTTP/2 协议的加持(底层传输协议,可替换为其他协议),使得 gRPC 的传输性能要优于传统 Restful。
protobuf 对于数据传输的优点有很多,如 支持流式传输,不过这就不是本文所述的内容了。总之你只要知道 grpc 性能高的原因就是因为 protobuf。
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 下的函数就是双方之间的预先定义好要以什么样的数据发送,又以什么样的数据返回。
我个人是觉得没什么特别重点的部分,根据自己的需求然后修改基本数据结构便可。