gRPCurl
grpcurl
是一个命令行工具,可让你与 gRPC 服务器交互。它基本上是 gRPC 服务器的 curl
。
这个工具的主要目的是从命令行调用 gRPC 服务器上的 RPC 方法。gRPC 服务器在网络上使用二进制编码(协议缓冲区,简称 "protobufs")。因此,使用普通的 curl
基本上无法与其交互(而且不支持 HTTP/2 的旧版本 curl
当然更不可能)。这个程序使用 JSON 编码接受消息,这对人类和脚本来说都更友好。
使用这个工具,你还可以浏览 gRPC 服务的架构,可以通过查询支持服务器反射的服务器,读取 proto 源文件,或加载编译好的 "protoset" 文件(包含编码文件描述符 protos的文件)。事实上,该工具将 JSON 请求数据转换为二进制编码的 protobuf 的方式正是使用了这个架构。因此,如果你交互的服务器不支持反射,你要么需要定义服务的 proto 源文件,要么需要 grpcurl
可以使用的 protoset 文件。
这个仓库还提供了一个库包 github.com/fullstorydev/grpcurl
,其中包含了简化构建其他动态调用 gRPC 端点的命令行工具的函数。这段代码是如何使用 protoreflect 库的各种包的绝佳示例,展示了它们能做什么。
另请参阅 GopherCon 2018 上的 grpcurl
演讲。
特性
grpcurl
支持所有类型的 RPC 方法,包括流式方法。你甚至可以通过在交互式终端中运行 grpcurl
并使用 stdin 作为请求体来交互式地操作双向流方法!
grpcurl
支持安全/TLS 服务器和明文服务器(即无 TLS),并有多种 TLS 配置选项。它还支持相互 TLS,其中客户端需要提供客户端证书。
如上所述,如果服务器支持反射服务,grpcurl
可以无缝工作。如果不支持,你可以向 grpcurl
提供 .proto
源文件或 protoset 文件(包含由 protoc
生成的编译描述符)。
安装
二进制文件
从发布页面下载二进制文件。
Homebrew(macOS)
在 macOS 上,可以通过 Homebrew 安装 grpcurl
:
brew install grpcurl
Docker
对于支持 Docker 的平台,你可以下载一个允许运行 grpcurl
的镜像:
# 下载镜像
docker pull fullstorydev/grpcurl:latest
# 运行工具
docker run fullstorydev/grpcurl api.grpc.me:443 list
注意使用 docker 时有一些陷阱:
- 如果需要与主机环回网络上监听的服务器交互,你必须将主机指定为
host.docker.internal
,而不是localhost
(适用于 Mac 或 Windows)或者让容器使用主机网络,使用-network="host"
(仅限 Linux)。 - 如果需要提供 proto 源文件或描述符集,你必须将包含这些文件的文件夹挂载为卷(
-v $(pwd):/protos
),并相应地调整导入路径为容器路径。 - 如果想通过 stdin 提供请求消息,使用
-d @
选项,你需要在 docker 命令上使用-i
标志。
其他包
感谢第三方创建的配方/包,还有许多其他安装 grpcurl
的方法。这些方法包括在各种环境下安装 grpcurl
的其他方式,包括 Windows 和众多 Linux 发行版。
你可以在 repology.org 上查看更多详情和 grpcurl
的完整其他包列表:
https://repology.org/project/grpcurl/information
从源码安装
如果你已经安装了 Go SDK,可以使用 go
工具安装 grpcurl
:
go install github.com/fullstorydev/grpcurl/cmd/grpcurl@latest
这会将命令安装到你的 $GOPATH
环境变量指向的位置的 bin
子文件夹中。(如果你没有设置 GOPATH
环境变量,默认安装位置是 $HOME/go/bin
)。如果这个目录已经在你的 $PATH
中,那么你就可以直接使用了。
如果你已经将这个仓库拉取到不在 $GOPATH
中的位置,并想从源码构建,你可以 cd
进入仓库然后运行 make install
。
如果你遇到编译错误,并且使用的 Go SDK 版本低于 1.13,你可能有过时的 grpcurl
依赖版本。你可以通过运行 make updatedeps
来更新依赖。或者,如果你使用的是 Go 1.11 或 1.12,你可以在上述命令前加上 GO111MODULE=on
前缀,这也会使用正确的依赖版本进行构建(而不是你的 GOPATH
中可能已有的任何版本)。
使用方法
工具的使用文档解释了众多选项:
grpcurl -help
在下面的章节中,你会找到许多演示如何使用 grpcurl
的例子。
调用 RPC
在受信任的服务器(例如,没有自签名密钥或自定义 CA 的 TLS)上调用 RPC,该服务器不需要客户端证书并支持服务器反射,这是使用 grpcurl
最简单的操作。这个最小调用发送一个空请求体:
grpcurl grpc.server.com:443 my.custom.server.Service/Method
# 无 TLS
grpcurl -plaintext grpc.server.com:80 my.custom.server.Service/Method
要发送非空请求,使用 -d
参数。注意所有参数必须在服务器地址和方法名之前:
grpcurl -d '{"id": 1234, "tags": ["foo","bar"]}' \
grpc.server.com:443 my.custom.server.Service/Method
如示例所示,提供的主体必须是 JSON 格式。主体将被解析然后以 protobuf 二进制格式传输到服务器。
如果你想在命令管道中包含 grpcurl
,例如使用 jq
创建请求体时,你可以使用 -d @
,这告诉 grpcurl
从 stdin 读取实际请求体:
grpcurl -d @ grpc.server.com:443 my.custom.server.Service/Method <<EOM
{
"id": 1234,
"tags": [
"foor",
"bar"
]
}
EOM
列出服务
要列出服务器公开的所有服务,使用"list"动词。当使用.proto
源文件或protoset文件而不是服务器反射时,这会列出源文件或protoset文件中定义的所有服务。
# 服务器支持反射
grpcurl localhost:8787 list
# 使用编译后的protoset文件
grpcurl -protoset my-protos.bin list
# 使用proto源文件
grpcurl -import-path ../protos -proto my-stuff.proto list
# 导出proto文件(使用-proto-out-dir指定输出目录)
grpcurl -plaintext -proto-out-dir "out_protos" "localhost:8787" describe my.custom.server.Service
# 导出protoset文件(使用-protoset-out指定输出文件)
grpcurl -plaintext -protoset-out "out.protoset" "localhost:8787" describe my.custom.server.Service
"list"动词还允许你查看特定服务中的所有方法:
grpcurl localhost:8787 list my.custom.server.Service
描述元素
"describe"动词将打印服务器知道的或在给定protoset文件中找到的任何符号的类型。它还会以proto源代码片段的形式打印该符号的描述。这不一定是定义该元素的原始源代码,但会是等效的。
# 服务器支持反射
grpcurl localhost:8787 describe my.custom.server.Service.MethodOne
# 使用编译后的protoset文件
grpcurl -protoset my-protos.bin describe my.custom.server.Service.MethodOne
# 使用proto源文件
grpcurl -import-path ../protos -proto my-stuff.proto describe my.custom.server.Service.MethodOne
描述符来源
grpcurl
工具可以操作各种描述符来源。描述符是必需的,以便grpcurl
能够理解RPC架构,将输入转换为protobuf二进制格式,并将响应从二进制格式转换为文本。以下部分记录了支持的来源以及使用它们所需的命令行标志。
服务器反射
如果没有任何额外的命令行标志,grpcurl
将尝试使用服务器反射。
设置服务器反射的示例可以在这里找到。
使用反射时,即使是"list"和"describe"操作,也需要服务器地址(主机:端口或Unix套接字路径),以便grpcurl
可以连接到服务器并请求其描述符。
Proto源文件
对于不支持反射的服务器,你可以使用.proto
源文件来使用grpcurl
。
除了使用-proto
标志指向相关的proto源文件外,你可能还需要提供-import-path
标志来告诉grpcurl
可以从哪些文件夹导入依赖项。
就像使用protoc
编译时一样,你不需要为protoc
附带的标准protos的位置提供导入路径(这些文件包含各种包定义为google.protobuf
的"众所周知的类型")。grpcurl
已经"知道"这些文件,因为它们的描述符快照已内置在grpcurl
二进制文件中。
使用proto源文件时,在使用"list"和"describe"操作时可以省略服务器地址(主机:端口或Unix套接字路径),因为它们只需要查询proto源文件。
Protoset文件
你也可以使用编译后的protoset文件与grpcurl
一起使用。如果你正在编写grpcurl
脚本并需要为多次调用重复使用相同的proto源,使用protoset文件会有更好的性能(因为它跳过了每次调用的解析和编译步骤)。
Protoset文件包含二进制编码的google.protobuf.FileDescriptorSet
protos。要创建protoset文件,使用定义服务的*.proto
文件调用protoc
:
protoc --proto_path=. \
--descriptor_set_out=myservice.protoset \
--include_imports \
my/custom/server/service.proto
--descriptor_set_out
参数告诉protoc
生成protoset,而--include_imports
参数对于protoset包含grpcurl
处理和理解架构所需的所有内容是必要的。
使用protoset时,在使用"list"和"describe"操作时可以省略服务器地址(主机:端口或Unix套接字路径),因为它们只需要查询protoset文件。