使用 grpcurl 通过命令行访问 gRPC 服务

使用 grpcurl 通过命令行访问 gRPC 服务

什么是grpcurl

grpcurl 是由 FullStory 基于 Go 编写的开源工具的一个命令行工具,用于与 gRPC 服务进行交互。它提供了一种简单的方式来测试、调试和探索 gRPC 服务,支持发送 gRPC 请求并查看响应。grpcurl 支持基于命令行的 gRPC 请求和响应,可以执行各种操作。

  • grpcurl支持各种类型的RPC方法,甚至可以通过在交互式终端中运行grpcurl并将stdin用作请求正文来交互式地操作
  • grpcurl支持安全/TLS服务器和纯文本服务器,并具有许多用于TLS配置的选项
  • 可以发送 gRPC 请求并查看响应,从而方便地测试和调试 gRPC 服务
  • 支持使用纯文本或 JSON 格式进行 gRPC 请求和响应的交互
  • 如果服务器支持反射服务,则grpcurl可以无缝工作

安装

Mac

brew install grpcurl

If you already have the Go SDK installed, you can use the go tool to install grpcurl:

go install github.com/fullstorydev/grpcurl/cmd/grpcurl@latest

Snap
You can install grpcurl using the snap package:

snap install grpcurl

下载官方二进制文件方式

curl -L https://github.com/fullstorydev/grpcurl/releases/download/v1.9.2/grpcurl_1.9.2_linux_x86_64.tar.gz -o grpcurl.tar.gz
tar -xvf grpcurl.tar.gz
sudo mv grpcurl /usr/local/bin/
grpcurl -version

尝试国内镜像加速(如果服务器在中国大陆)

# 尝试使用 ghproxy.com 加速
curl -L https://mirror.ghproxy.com/https://github.com/fullstorydev/grpcurl/releases/download/v1.9.2/grpcurl_1.9.2_linux_x86_64.tar.gz -o grpcurl.tar.gz

Invoking RPCs示例

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

向请求添加标头/元数据

grpcurl -H header1:value1 -H header2:value2 -d '{"id": 1234, "tags": ["foo","bar"]}' grpc.server.com:443 my.custom.server.Service/Method

工作常见总结

tls: first record does not look like a TLS handshake

grpcurl 127.0.0.1:8001 list
Failed to dial target host "127.0.0.1:8001": tls: first record does not look like a TLS handshake

报错信息 tls: first record does not look like a TLS handshake 的意思是:grpcurl 默认尝试建立加密链接(TLS),但服务端(127.0.0.1:8001)返回的是非加密(明文)的数据。

这意味着您的 gRPC 服务没有开启 TLS。

解决方法
请在命令中加上 -plaintext 参数:

  • 默认行为:grpcurl 默认假定服务是安全的(类似 HTTPS)。
  • -plaintext:告诉 grpcurl 不要使用 TLS,直接发送明文数据(类似 HTTP)。这在本地调试或内网环境中非常常见。

server does not support the reflection API

grpcurl -plaintext  127.0.0.1:8001 list
Failed to list services: server does not support the reflection API

grpcurl 需要服务器开启 Server Reflection (反射服务) 才能自动获取服务列表。

方法一:提供 .proto 文件(客户端解决)

如果您手头有该服务的 .proto 定义文件(通常开发代码里都有),您可以直接把文件喂给 grpcurl,这样它就不需要问服务器了。

假设您的文件叫 myservice.proto

grpcurl -plaintext -proto myservice.proto 127.0.0.1:8001 list

如果有多个 proto 文件引用,可能还需要 -import-path 参数指向目录。

方法二:在代码中开启反射(服务端解决 - 推荐)

如果您是这个服务的开发者,最方便的方法是在服务端代码里加一行开启反射的代码。

以 Go 语言 为例(最常见的 gRPC 语言):

导入包:

import "google.golang.org/grpc/reflection"

注册反射服务(在 s := grpc.NewServer() 之后):

s := grpc.NewServer()
// ... 注册您的业务服务 ...

// 开启反射服务(加这一行)
reflection.Register(s) 

// 启动服务
s.Serve(lis)

重启服务,然后再运行 grpcurl … list 就能成功了。

【重要】知道方法名是 com.example.MyService/SayHello 后 为什么构造的命令还需要-proto 参数?

简单来说:知道“方法名”只相当于知道了“快递要送到哪里”,但 .proto 文件决定了“快递怎么打包”。

这里有一个核心概念:gRPC 传输的不是 JSON,而是二进制数据(Protobuf)。

以下是必须提供 -proto 的三个具体原因:

  1. 必须进行“翻译”(序列化)
    您在命令行里输入的是 JSON 格式(例如 {"name": "ZhangSan"}),但服务器只能听懂 二进制 格式。

grpcurl 作为一个客户端,它的工作是把您的 JSON 翻译成二进制发给服务器

没有 Proto 文件时:grpcurl 看着 name 这个字段一脸茫然——它是第几个字段?它是 String 还是 Int?它该被压缩成什么样?
有 Proto 文件时:文件里写着 string name = 1;。grpcurl 就会明白:“哦!用户输入的 name 对应的是 序号 1,类型是 字符串。”
然后它才能生成正确的二进制数据发给服务器。

  1. 字段映射(Tag ID)
    在 gRPC/Protobuf 的世界里,数据传输时不传“字段名”(比如 name 这个词是不传输的),只传“字段序号(Tag ID)”。

请看这个对比:

JSON (您输入的): {"name": "ZhangSan", "age": 18}
Proto 定义:

message Request {
  string name = 1; // 关键在于这个 1
  int32 age = 2;   // 关键在于这个 2
}

实际网络传输: 1: “ZhangSan”, 2: 18 (实际上是二进制编码)
如果您不提供 -proto,grpcurl 就不知道 name 应该映射成 1 还是 100,也就无法生成服务器能读懂的数据包。

  1. 响应数据的解码
    同样的道理,当服务器返回数据给您时,它发回来的也是一堆二进制代码(比如 0A 05 48 65 6C 6C 6F)。

如果不提供 .proto,grpcurl 收到这堆数据后,完全不知道怎么把它还原成您能看懂的 JSON 文字。
有了 .proto,它才知道:“收到了序号 1 的数据,它是字符串,内容是 Hello”,然后打印在屏幕上给您看。

总结:
方法名 (com.example…):告诉网络路由怎么走。
Proto 文件:告诉客户端数据怎么编码和解码。
只有开启了服务端反射,服务器才会把这本“字典”(Proto定义)直接告诉客户端,您才不需要自己在命令里带上它。既然反射没开,您就必须自己带上这本“字典”。

生产环境是否开启反射

一般不推荐在生产环境开启反射,除非是在严格受控的内网环境中。

反射会暴露所有的服务名、方法名、参数结构甚至注释。
攻击者不再需要猜接口,直接 grpcurl list 就能看到你的全套 API。如果有一些并未公开的、内部的、或者是旧版本的“僵尸接口”忘了删,攻击者一眼就能发现并尝试攻击。

【重要】什么时候“可以”开反射?
  • 纯内网微服务:
    如果你的 gRPC 服务完全运行在 Kubernetes 集群内部,且外部流量无法直接接触到 gRPC 端口(只能通过 API Gateway 访问 HTTP),那么开启反射问题不大,反而有利于运维排查。
  • 公共 API 服务:
    如果你的产品本身就是对外开放的 API(类似于 gRPC 版的 Stripe 或 GitHub API),本来就要给用户文档,那么开启反射作为一种“动态文档”也是可以的(但通常大厂还是倾向于提供 SDK 或 Proto 文件下载,而不是开反射)。

总结

  • 开发/测试环境:强烈推荐开启。极大地提高调试效率。
  • 生产环境:默认关闭。
  • 折中办法:如果你是运维,生产环境需要抓包调试,应该建立一个 Proto 文件仓库(Schema Registry)。调试时从仓库拉取 .proto 文件,配合 grpcurl -proto 命令使用,而不是依赖服务器的反射
  • 场景:Kubernetes 集群内部的微服务。运维价值极大:当线上出现紧急故障(比如某个微服务挂了或者数据不对),SRE 或开发人员跳板机连上去,直接敲 grpcurl … list 就能立刻测试,比去翻代码库找 .proto 文件再传上去要快得多。在故障处理中,时间就是金钱。
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

西京刀客

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值