基于 Protobuf 创建 gRPC 网关服务开发指南
为什么使用 gRPC 网关?
gRPC 网关(gRPC Gateway)的核心目的是将 gRPC 服务暴露为 HTTP/JSON API,同时提供更灵活的 API 管理能力。它的主要优势包括:
兼容性强
让 gRPC 服务支持 HTTP/JSON 请求,方便浏览器、移动端或旧系统调用,无需直接处理 gRPC 协议。开发效率高
通过 Protobuf 定义自动生成 RESTful 路由和 Swagger 文档,减少手动编写重复代码。性能与通用性平衡
内部使用高效的 gRPC 通信,对外提供通用的 HTTP 接口,适合混合架构场景。简化过渡
逐步迁移系统时,可先通过网关暴露 HTTP API,内部仍用 gRPC,降低改造风险。聚合多个 gRPC 服务 API
可以在网关层整合多个微服务的 gRPC 接口,对外提供统一的 HTTP 入口,减少客户端直接调用多个服务的复杂性。
gRPC 网关是 gRPC 微服务与 RESTful 客户端之间的桥梁,既能提升内部通信效率,又能提供灵活、统一的对外 API。
概述
基于 protobuf 创建 gRPC 网关服务
为通用的 gRPC 网关服务开发提供了一套完整的解决方案。该方案让开发者只需专注于实现调用 gRPC 服务的业务逻辑,而其他基础代码(如框架代码、接口定义等)均由 sponge 自动生成。
适用场景:
- 对外暴露 RESTful API,内部使用 gRPC 的服务。
- 聚合多个微服务的 API。
- 旧系统使用 REST,新服务用 gRPC,通过网关逐步迁移。
前期准备
环境要求:
- 已安装 sponge
- proto 文件(例如 user_gw.proto)
- gRPC 服务(例如 user,也可以临时快速创建一个 gRPC 服务)
创建 gRPC 网关服务
在终端执行命令sponge run
进入生成代码 UI 界面:
- 点击左边菜单栏【Protobuf】 → 【创建 gRPC 网关服务】;
- 选择 proto 文件(可多选);
- 接着填写其他参数,鼠标放在问号
?
位置可以查看参数说明。
提示
如果填写参数启用了大仓库类型
选项,后续所有相关代码生成都需保持此设置。
填写完参数后,点击按钮下载代码
生成 gRPC 网关服务代码,如下图所示:

等价命令
sponge micro rpc-gw-pb --module-name=user_gw --server-name=user_gw --project-name=edusys --protobuf-file=./user_gw.proto
提示
生成的 gRPC 网关服务代码目录默认命名为
服务名称-类型-时间
格式,您可根据实际需要自行修改该目录名称。系统会自动保存成功生成的代码记录,方便下一次生成代码使用,刷新或重新打开页面时显示上一次部分参数。
目录结构
生成的代码目录结构如下:
.
├─ api
│ └─ edusys
│ └─ v1
├─ cmd
│ └─ edusys
│ ├─ initial
│ └─ main.go
├─ configs
├─ deployments
│ ├─ binary
│ ├─ docker-compose
│ └─ kubernetes
├─ docs
├─ internal
│ ├─ config
│ ├─ ecode
│ ├─ routers
│ ├─ server
│ └─ service
├─ scripts
└─ third_party
代码结构示意图
创建的 gRPC 网关服务代码采用的"鸡蛋模型"架构:

代码调用链路说明
sponge 生成的 gRPC 网关服务代码采用分层架构,完整调用链路如下:
cmd/user/main.go
→ internal/server/http.go
→ internal/routers/router.go
→ internal/service
其中 service 层主要负责 API 调用的具体实现,若有复杂的业务逻辑,建议额外添加专门处理业务逻辑层(例如internal/biz
或其他)。
测试 gRPC 网关服务代码
解压代码文件,打开终端,切换到 web 服务代码目录,执行命令:
# 生成与合并 api 相关代码
make proto
# 编译和运行服务
make run
make proto
命令详解
使用建议
仅当 proto 文件中 API 描述发生变更时才需执行该命令,否则跳过该命令,直接运行make run
命令。该命令会后台执行以下自动化操作
- 生成
*.pb.go
文件 - 生成路由注册代码
- 生成错误码定义
- 生成 Swagger 文档
- 生成 API 模板代码
- 自动合并 API 模板代码
- 生成
安全机制
- 代码合并时会保留原有业务逻辑
- 每次合并前会自动备份代码至:
- Linux/Mac:
/tmp/sponge_merge_backup_code
- Windows:
C:\Users\[用户名]\AppData\Local\Temp\sponge_merge_backup_code
- Linux/Mac:
在浏览器打开 Swagger 页面 http://localhost:8080/apis/swagger/index.html,可以在页面上查看 API 文档。
注意
在未实现业务逻辑前,Swagger 请求将返回500错误。这是因为生成的模板代码(internal/handler/xxx.go
)中每个方法都包含panic("implement me")
代码,提示开发者自行实现或内置的 AI 助手生具体业务逻辑。
Swagger 配置说明
如果您在configs/服务名称.yml
配置文件中修改了 HTTP 端口(例如从8080改为9090),必须同步完成以下操作:
- 修改代码文件
cmd/服务名/main.go
中的@host
值为新端口(如 localhost:9090) - 重新执行
make docs
生成文档
否则会因端口不一致导致 API 请求失败。
跨服务 gRPC API 调用
在微服务架构中,当前服务可能需要调用其他 gRPC 服务提供的 API。这些目标服务可能采用不同语言实现,但都需使用 Protocol Buffers 协议。以下是完整的调用流程说明:
生成 gRPC 服务连接代码
操作步骤:
- 访问 sponge UI 界面
- 导航至【Public】→【生成 gRPC 服务连接代码】
- 填写参数:
- Module 名称(必填)
- gRPC 服务名称(支持多个服务,用逗号分隔)
点击按钮【下载代码】生成 gRPC 服务连接代码,如下图所示:

等价命令
# 完整命令
sponge micro rpc-conn --module-name=user_gw --rpc-server-name=user
# 简化命令(使用 --out 指定服务代码目录,生成代码自动合并到指定服务目录)
sponge micro rpc-conn --rpc-server-name=user --out=user_gw
生成代码结构:
.
└─ internal
└─ rpcclient # 包含服务发现、负载均衡等完整客户端配置
解压代码,把目录internal
移动到本服务代码目录下。
在代码中使用生成的 gRPC 连接代码示例:
实际使用中有可能需要从多个 gRPC 服务中调用 API 获取数据,初始化示例代码如下:
package service
import (
userV1 "edusys/api/user/v1"
relationV1 "edusys/api/relation/v1"
creationV1 "edusys/api/creation/v1"
// ......
)
type userClient struct {
relationCli relationV1.RelationClient
creationCli creationV1.CreationClient
}
// NewUserClient create a client
func NewUserClient() edusysV1.UserLogicer {
return &userClient{
// 实例化多个 gRPC 服务 client 接口
relationCli: userV1.NewRelationClient(rpcclient.GetRelationRPCConn()),
creationCli: userV1.NewCreationClient(rpcclient.GetCreationRPCConn()),
}
}
// ......
配置目标 gRCP 服务连接参数
在配置文件 configs/服务名称.yml
中添加以下配置:
grpcClient:
- name: "user" # grpc 服务名称
host: "127.0.0.1" # grpc 服务地址,如果开启服务发现,此字段值无效
port: 8282 # grpc 服务端口,如果开启服务发现,此字段值无效
registryDiscoveryType: "" # 服务发现,默认关闭,支持 consul, etcd, nacos
多服务配置示例:
grpcClient:
- name: "user"
host: "127.0.0.1"
port: 18282
registryDiscoveryType: ""
- name: "relation"
host: "127.0.0.1"
port: 28282
registryDiscoveryType: ""
- name: "creation"
host: "127.0.0.1"
port: 38282
registryDiscoveryType: ""
提示
完整配置选项可参考配置文件configs/[服务名称].yml
的 grpcClient
字段说明。
调用目标 gRPC 服务 API
成功连接到目标 gRPC 服务后,为了明确可调用的 API 接口,需要引入由 proto 文件生成的 Go 语言桩代码。根据服务架构的不同,调用方式主要分为以下两种情况:
单仓库(Mono-repo)架构
如果目标 gRPC 服务由 sponge 创建,并且与本服务同属一个微服务单仓库(创建服务时选择"大仓库"类型),则可以直接调用其 API,不存在跨服务依赖问题。多仓库(Multi-repo)架构
如果目标 gRPC 服务位于独立的代码仓库,则需要解决跨服务引用 proto 文件和 Go 桩代码的问题。以下是两种常用解决方案:方案一:使用公共 Protobuf 仓库
对于多仓库架构的微服务系统,建议创建专门的公共 Git 仓库(如
public_protobuf
)集中管理 proto 文件及其生成的 Go 桩代码。典型目录结构如下:· ├── api │ ├── serverName1 │ │ └── v1 │ │ ├── serverName1.pb.go │ │ └── serverName1_grpc.pb.go │ └── serverName2 │ └── v1 │ ├── serverName2.pb.go │ └── serverName2_grpc.pb.go ├── protobuf │ ├── serverName1 │ │ └── serverName1.proto │ └── serverName2 │ └── serverName2.proto ├── go.mod └── go.sum
调用步骤:
将公共仓库中的
protobuf
目录复制到本地服务的third_party
目录. ├── third_party │ └── protobuf │ ├── serviceA │ │ └── serviceA.proto │ └── serviceB │ └── serviceB.proto
在本地 proto 文件中通过 import 引入目标 proto(如
import "protobuf/serviceA/serviceA.proto";
)在本地服务的 service 中调用目标 gRPC 服务的 API。
注
需确保
third_party/protobuf
下的 proto 文件与公共仓库保持同步。方案二:将目标服务的 proto 文件复制到本服务中,并生成 Go 语言桩代码
根据目标服务的创建方式,采用不同处理流程:
非 sponge 创建的服务
- 手动将目标服务的 proto 文件复制到
api/目标服务名/v1
目录 - 需人工修改 proto 文件中的
go_package
路径定义
- 手动将目标服务的 proto 文件复制到
sponge 创建的服务
通过自动化命令完成集成:
# 复制目标服务的 proto 文件(支持多服务目录,用逗号分隔) make copy-proto SERVER=../target_service_dir # 生成 Go 桩代码 make proto
高级选项:
- 指定 proto 文件:
PROTO_FILE=file1,file2
- 自动备份:被覆盖的文件可在
/tmp/sponge_copy_backup_proto_files
找回
- 指定 proto 文件:
测试跨服务调用 gRPC API
启动依赖服务:
- sponge 创建的 gRPC 服务:例如 user,执行
make run
- 其他 gRPC 服务:按实际启动命令运行
- sponge 创建的 gRPC 服务:例如 user,执行
启动本服务,执行命令:
# 生成与合并 api 相关代码 make proto # 编译和运行服务 make run
在浏览器打开 Swagger 页面 http://localhost:8080/apis/swagger/index.html,在页面上测试 API。
开发自定义 API
在 gRPC 网关服务中,除了跨服务调用 API 外,可能需要添加新的自定义 API,sponge 采用"定义即生成"的开发模式,可快速实现自定义 API 开发,主要分为以下三个步骤:
定义 API
在.proto
文件中声明 API 的请求/响应格式实现逻辑
在自动生成的代码模板中填充核心业务逻辑代码测试验证
在内置的 Swagger 测试 API,无需依赖 Postman 等第三方工具
以下以添加"修改密码" API 为例,详细说明开发流程。
1. 定义 API
进入项目目录api/edusys/v1
目录,打开文件user_gw.proto
,添加修改密码 API 的描述信息:
import "validate/validate.proto";
import "tagger/tagger.proto";
service user {
// ...
// 修改密码,在这里描述实现具体实现逻辑,告诉 sponge 内置的 AI 助手生成的业务逻辑代码
rpc ChangePassword(ChangePasswordRequest) returns (ChangeRegisterReply) {
option (google.api.http) = {
post: "/api/v1/user/change_password"
body: "*"
};
option (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_operation) = {
summary: "修改密码",
description: "修改密码",
security: {
security_requirement: {
key: "BearerAuth";
value: {}
}
}
};
}
}
message ChangePasswordRequest {
uint64 id = 1 [(validate.rules).uint64.gte = 1, (tagger.tags) = "uri:\"id\"" ];
string password = 2 [(validate.rules).string.min_len = 6];
}
message ChangePasswordReply {
}
添加 api 描述信息后,在终端执行命令:
# 生成与合并 api 相关代码
make proto
2. 实现业务逻辑
实现业务逻辑代码有两种方式:
人工编写业务逻辑代码
打开代码文件
internal/handler/user.go
,在 ChangePassword 方法函数下参考模板代码编写业务逻辑代码。自动生成业务逻辑代码
sponge 提供了内置 AI 助手生成业务逻辑代码,点击查看 AI 助手生成代码章节。
AI 助手生成的业务逻辑代码可能不完全符合实际需求,需要根据实际情况进行修改。
3. 测试自定义 API
实现业务逻辑代码后,在终端执行命令:
# 编译和运行服务
make run
在浏览器刷新 Swagger 界面 http://localhost:8080/apis/swagger/index.html,在页面上进行测试自定义 API。
服务配置说明
基于 protobuf 创建 web 服务
方案提供了丰富的可配置组件,您可以通过修改configs/服务名称.yml
配置文件来灵活管理这些组件。
组件管理说明
自定义 gin 中间件:
- 可在
internal/routers/routers.go
中添加、替换中间件。 - 如需 API 鉴权,在
internal/routers/表名.go
中添加middleware.Auth()
。
默认启用的组件
组件 | 功能说明 | 配置文档 |
---|---|---|
logger | 日志组件 • 默认终端输出 • 支持 console/json 格式 • 支持日志文件分割和保留 | 日志配置 |
enableMetrics | Prometheus 指标采集 • 默认路由 /metrics | 监控配置 |
enableStat | 资源监控 • 每分钟记录 CPU/内存使用率 • 超过阈值自动保存 profile | 资源统计 |
默认关闭的组件
组件 | 功能说明 | 配置文档 |
---|---|---|
cacheType | 缓存支持(Redis/内存) | redis 配置 |
enableHTTPProfile | 性能分析(pprof) • 默认路由 /debug/pprof/ | - |
enableLimit | 自适应请求限流 | 限流配置 |
enableCircuitBreaker | 服务熔断保护 | 熔断配置 |
enableTrace | 分布式链路追踪 | 链路追踪配置 |
registryDiscoveryType | 服务注册与发现 • Consul/Etcd/Nacos | 服务注册与发现配置 |
grpcClient | grpc 客户端连接设置 • 服务名称、地址、端口 • 服务发现类型 • 超时设置、负载均衡 • 证书验证、token 验证 | gRPC 客户端配置 |
配置更新流程
如果添加或更改配置文件configs/服务名称.yml
字段名,需要更新对应的 Go 代码,在终端执行命令:
# 重新生成配置代码
make config
注
如果只修改配置文件的字段值,不需要执行make config
命令,只需重新编译运行即可。
提示
如需了解更多组件与配置的详细信息,点击查看 组件与配置章节。