Appearance
如何使用 grpcurl 命令行工具测试你的 gRPC 服务

像 curl 测试 HTTP 接口一样测试 gRPC 服务 —— grpcurl 工具完整教程
1. 什么是 grpcurl?
grpcurl 是一个命令行工具,用于与 gRPC 服务器进行交互。它的设计灵感来自 curl,但专门针对 gRPC 协议进行了优化。
核心功能
| 功能 | 说明 |
|---|---|
| 调用 gRPC 方法 | 像 curl 调用 REST API 一样调用 gRPC 服务 |
| 服务发现 | 通过 gRPC 反射自动获取服务定义 |
| 多协议支持 | 支持 HTTP/2、TLS、Unix Socket |
| 多种数据格式 | 支持 JSON、Protobuf Text 格式 |
| 流式调用 | 支持服务端流、客户端流、双向流 |
适用场景
- 开发阶段调试 gRPC 服务
- 验证服务接口是否正常工作
- 快速测试 API 返回结果
- CI/CD 中的接口测试
2. 安装 grpcurl
方式一:使用 Go 安装(推荐)
bash
# 安装最新版本
go install github.com/fullstorydev/grpcurl/cmd/grpcurl@latest
# 验证安装
~/go/bin/grpcurl --version方式二:使用 Homebrew (macOS)
bash
brew update
brew install grpcurl
grpcurl --version方式三:下载预编译二进制
访问 GitHub Releases 下载对应平台的二进制文件。
bash
# 示例:下载 Linux amd64 版本
curl -L https://github.com/fullstorydev/grpcurl/releases/download/v1.9.3/grpcurl_1.9.3_linux_x86_64.tar.gz -o grpcurl.tar.gz
tar -xzf grpcurl.tar.gz
sudo mv grpcurl /usr/local/bin/验证安装
bash
grpcurl --version
# grpcurl 1.9.33. 基础用法
3.1 查看服务列表
bash
# 通过反射列出所有服务
grpcurl -plaintext localhost:50051 list
# 输出示例
# grpc.health.v1.Health
# grpc.reflection.v1alpha.ServerReflection
# discovery.v1.DiscoveryAgent3.2 查看服务方法
bash
# 列出特定服务的所有方法
grpcurl -plaintext localhost:50051 list discovery.v1.DiscoveryAgent
# 输出示例
# discovery.v1.DiscoveryAgent.Status
# discovery.v1.DiscoveryAgent.Heartbeat
# discovery.v1.DiscoveryAgent.Reload
# discovery.v1.DiscoveryAgent.Verify
# discovery.v1.DiscoveryAgent.StreamHeartbeat3.3 查看方法详情
bash
# 查看方法的请求/响应结构
grpcurl -plaintext localhost:50051 describe discovery.v1.DiscoveryAgent.Status
# 输出示例
# discovery.v1.DiscoveryAgent.Status is a method:
# rpc Status ( .discovery.v1.StatusRequest ) returns ( .discovery.v1.StatusResponse );3.4 调用 gRPC 方法
bash
# 无参数调用
grpcurl -plaintext localhost:50051 discovery.v1.DiscoveryAgent/Status
# 带参数调用
grpcurl -plaintext -d '{"timestamp": 1723456789}' localhost:50051 discovery.v1.DiscoveryAgent/Heartbeat4. Unix Socket 调试(重点!)
4.1 版本差异
不同版本的 grpcurl 对 Unix Socket 的支持方式不同:
| 版本 | 正确格式 | 说明 |
|---|---|---|
| v1.8.7 及以下 | -unix /path/to/socket | 使用 -unix 标志 |
| v1.9.0 及以上 | unix:///path/to/socket | 使用 URL 格式(推荐) |
4.2 v1.9.0+ 的调用方式
bash
# 基本格式:grpcurl [flags] [address] [service/method]
# address 格式:unix:///path/to/socket(三个斜杠)
# 基本调用
grpcurl -plaintext unix:///tmp/discovery-agent.sock discovery.v1.DiscoveryAgent/Status
# 带参数调用
grpcurl -plaintext -d '{"timestamp": 1723456789}' unix:///tmp/discovery-agent.sock discovery.v1.DiscoveryAgent/Heartbeat
# 无参调用
grpcurl -plaintext -d '{}' unix:///tmp/discovery-agent.sock discovery.v1.DiscoveryAgent/Reload4.3 注意点
| 要点 | 说明 |
|---|---|
必须加 -plaintext | Unix Socket 没有 TLS,不加会报 TLS 错误 |
| 地址格式 | 必须使用 unix:///path/to/socket(三个斜杠) |
| -d 参数位置 | 放在服务名前面 |
| 服务名格式 | package.Service/Method |
4.4 常见错误及解决方案
| 错误 | 原因 | 解决方案 |
|---|---|---|
missing port in address | 未使用 unix:// 格式 | 使用 unix:///path/to/socket |
first record does not look like a TLS handshake | 未加 -plaintext | 添加 -plaintext 标志 |
Too many arguments | 参数顺序或格式错误 | 检查 -d 参数格式 |
5. 高级用法
5.1 使用 -d @ 从标准输入读取
当 JSON 数据较大或包含特殊字符时,可以使用 -d @ 从标准输入读取:
bash
# 使用 echo
echo '{"timestamp": 1723456789}' | grpcurl -plaintext -d @ unix:///tmp/discovery-agent.sock discovery.v1.DiscoveryAgent/Heartbeat
# 使用 here-document
grpcurl -plaintext -d @ unix:///tmp/discovery-agent.sock discovery.v1.DiscoveryAgent/Heartbeat <<EOF
{"timestamp": 1723456789}
EOF
# 从文件读取
grpcurl -plaintext -d @ unix:///tmp/discovery-agent.sock discovery.v1.DiscoveryAgent/Heartbeat < request.json5.2 使用反射 vs 使用 proto 文件
方式一:使用反射(推荐,需要服务端支持)
bash
grpcurl -plaintext localhost:50051 list
grpcurl -plaintext localhost:50051 describe discovery.v1.DiscoveryAgent方式二:使用 proto 文件(反射不可用时)
bash
grpcurl -plaintext -proto api/v1/discovery.proto \
-import-path ./api/v1 \
localhost:50051 discovery.v1.DiscoveryAgent/Status5.3 添加自定义 Header
bash
# 添加自定义 Header
grpcurl -plaintext -H "X-API-Key: abc123" \
localhost:50051 discovery.v1.DiscoveryAgent/Status
# 添加多个 Header
grpcurl -plaintext -H "Authorization: Bearer token123" \
-H "X-Request-ID: 12345" \
localhost:50051 discovery.v1.DiscoveryAgent/Status5.4 流式调用
bash
# 服务端流(Server Streaming)
grpcurl -plaintext -d '{}' localhost:50051 package.Service/ServerStream
# 客户端流(Client Streaming)
grpcurl -plaintext -d @ localhost:50051 package.Service/ClientStream <<EOF
{"msg": "hello"}
{"msg": "world"}
EOF6. 实用技巧
6.1 格式化输出
bash
# 使用 jq 美化输出
grpcurl -plaintext unix:///tmp/discovery-agent.sock discovery.v1.DiscoveryAgent/Status | jq .
# 只提取特定字段
grpcurl -plaintext unix:///tmp/discovery-agent.sock discovery.v1.DiscoveryAgent/Status | jq '.modules'6.2 输出为 Protobuf Text 格式
bash
grpcurl -format text -plaintext localhost:50051 discovery.v1.DiscoveryAgent/Status6.3 调试请求/响应
bash
# 启用详细输出
grpcurl -v -plaintext localhost:50051 discovery.v1.DiscoveryAgent/Status
# 查看请求/响应头
grpcurl -vv -plaintext localhost:50051 discovery.v1.DiscoveryAgent/Status6.4 设置超时
bash
# 连接超时 10 秒,总超时 30 秒
grpcurl -connect-timeout 10 -max-time 30 \
-plaintext localhost:50051 discovery.v1.DiscoveryAgent/Status7. 在 Makefile 中使用
完整示例
makefile
# grpcurl 测试命令
grpcurl-status:
grpcurl -plaintext unix:///tmp/discovery-agent.sock discovery.v1.DiscoveryAgent/Status
grpcurl-heartbeat:
grpcurl -plaintext -d '{"timestamp": 1723456789}' unix:///tmp/discovery-agent.sock discovery.v1.DiscoveryAgent/Heartbeat
grpcurl-reload:
grpcurl -plaintext -d '{}' unix:///tmp/discovery-agent.sock discovery.v1.DiscoveryAgent/Reload
grpcurl-verify:
grpcurl -plaintext -d '{"discovery_data": ""}' unix:///tmp/discovery-agent.sock discovery.v1.DiscoveryAgent/Verify
# 从文件读取数据的版本
grpcurl-heartbeat-file:
grpcurl -plaintext -d @ unix:///tmp/discovery-agent.sock discovery.v1.DiscoveryAgent/Heartbeat < request.json使用示例
bash
make grpcurl-status
make grpcurl-heartbeat
make grpcurl-reload8. 与 curl 对比
| 功能 | curl | grpcurl |
|---|---|---|
| 协议 | HTTP/1.1, HTTP/2 | HTTP/2 (gRPC) |
| 数据格式 | JSON, XML, Form | JSON, Protobuf |
| 服务发现 | OpenAPI/Swagger | gRPC 反射 |
| Unix Socket | --unix-socket | unix:///path |
| 流式 | ❌ | ✅ (双向流) |
| TLS | ✅ | ✅ |
9. 常见问题 FAQ
Q1: grpcurl 报 Too many arguments
原因: 参数格式不正确。
解决方案:
- 检查
-d参数是否被正确解析 - 使用
-d @从标准输入读取数据
Q2: Unix Socket 报 missing port in address
原因: 未使用正确的 Unix Socket 地址格式。
解决方案:
bash
# 正确格式(v1.9.0+)
grpcurl -plaintext unix:///tmp/socket.sock service/methodQ3: 报 first record does not look like a TLS handshake
原因: 未添加 -plaintext 标志。
解决方案:
bash
grpcurl -plaintext localhost:50051 service/methodQ4: 如何查看 grpcurl 版本?
bash
grpcurl --versionQ5: 服务端未启用反射怎么办?
使用 -proto 指定 proto 文件:
bash
grpcurl -plaintext -proto api/v1/service.proto -import-path ./api/v1 localhost:50051 package.Service/Method