您现在的位置是:亿华云 > 数据库
Golang 语言 gRPC 服务怎么同时支持 gRPC 和 HTTP 客户端调用?
亿华云2025-10-03 09:03:54【数据库】1人已围观
简介01介绍关于 gRPC 的文章,我们之前写过几篇,如果读者朋友还对 gRPC 不了解,我建议您可以翻阅一下公众号的历史文章。当我们需要提供 gRPC 服务的 RESTful API 时,可以先创建一个
01介绍
关于 gRPC 的服务文章,我们之前写过几篇,支持如果读者朋友还对 gRPC 不了解,和H户端我建议您可以翻阅一下公众号的调用历史文章。
当我们需要提供 gRPC 服务的服务 RESTful API 时,可以先创建一个 gRPC 客户端服务,支持在 gRPC 客户端服务编写 RESTful API,和H户端接收到 HTTP 请求时,调用通过 gRPC 客户端服务调用 gRPC 服务端服务的服务方法。
相信读者朋友们也意识到,支持仅仅为了提供 RESTful API 而编写一个 gRPC 客户端服务,和H户端显然有些小题大做。调用
在不借助 gRPC 客户端服务的服务前提下,gRPC 服务端服务怎么同时支持 gRPC 和 HTTP 客户端调用?支持今天我们介绍一个 protoc 插件 gRPC-Gateway。
02gRPC-Gateway
gRPC-Gateway 是和H户端 protoc 的一个插件。它读取 gRPC 服务定义并生成一个反向代理服务器,该服务器将 RESTful JSON API 转换为 gRPC。此服务器是根据 gRPC 定义中的自定义选项生成的云南idc服务商。
gRPC-Gateway 可帮助您同时以 gRPC 和 RESTful 风格提供 API。
在我们开始编码之前,需要一些先决条件。
首先,我们需要先搭建一个 Go 环境。
使用 go get 工具下载一些依赖包。
使用 go mod init 工具创建一个 go.mod 文件。
依赖包列表:
$ go get github.com/grpc-ecosystem/grpc-gateway/v2/protoc-gen-grpc-gateway
$ go get google.golang.org/protobuf/cmd/protoc-gen-go
$ go get google.golang.org/grpc/cmd/protoc-gen-go-grpc03gRPC-Gateway 实战
在完成以上先决条件后,我们创建一个 gRPC 服务端服务,本文我们创建一个 ToDoList gRPC 服务。在创建 gRPC 服务之前,我们使用 protocol buffers 创建一个 proto 文件。
创建 proto 文件
...
service ToDoList {
rpc CreateToDoList (ToDoListDetail) returns (CreateToDoListResult) { }
rpc ReadToDoList (ToDoListPage) returns (ReadToDoListByPage) { }
}
...生成 gRPC 服务端存根
使用 protoc 命令工具生成存根
protoc -I proto \
--go_out ./pb/todoPb --go_opt paths=source_relative \
--go-grpc_out ./pb/todoPb --go-grpc_opt paths=source_relative \
proto/toDoList.proto执行上面 protoc 命令工具,生成一个 *.pb.go 文件和一个 *_grpc.pb.go 文件。
编写剩余 Go 代码
创建 main.go
func main() {
InitEngine()
lis, err := net.Listen("tcp", address)
if err != nil {
log.Fatalf("failed to listen: %v", err)
}
server := grpc.NewServer()
pb.RegisterToDoListServer(server, new(service.ToDoList))
log.Printf("server listening at %v\n", lis.Addr())
if err := server.Serve(lis); err != nil {
log.Fatalf("failed to serve: %v", err)
}
}添加 gRPC-Gateway 选项
gRPC-Gateway 使用 google.api.http 选项定义 gRPC 服务如何映射到 JSON 请求和响应,使用 protoc 时,每个 RPC 必须使用 google.api.http 选项定义 HTTP 方法和路径。
因此,我们需要将 google/api/http.proto 导入添加到 proto 文件中。我们还需要添加我们想要的 HTTP -> gRPC 映射。
syntax = "proto3";
import "google/api/annotations.proto";
service ToDoList {
rpc CreateToDoList (ToDoListDetail) returns (CreateToDoListResult) {
option (google.api.http) = {
post: "/v1/todolist/add"
body: "*"
};
}
rpc ReadToDoList (ToDoListPage) returns (ReadToDoListByPage) {
option (google.api.http) = {
get: "/v1/todolist/select"
};
}
}
...关于 HTTP 和 gRPC 映射的更多内容,可以参阅 Google API 文档。
生成 gRPC-Gateway 存根
现在,源码库我们已将 gRPC-Gateway 选项添加到 proto 文件中,我们需要使用 gRPC-Gateway 生成器来生成存根。
在使用 protoc 生成存根之前,我们需要将一些依赖项复制到 proto 文件目录中。将 googleapis 的子集从官方存储库下载并复制到本地 proto 文件目录中。如下所示:
.
├── dao
│ ├── mysql.go
│ └── toDoList.go
├── grpc-gateway
│ └── main.go
├── main.go
├── pb
│ └── todoPb
│ ├── toDoList.pb.go
│ ├── toDoList.pb.gw.go
│ └── toDoList_grpc.pb.go
├── proto
│ │ └── api
│ │ ├── annotations.proto
│ │ └── http.proto
│ └── toDoList.proto
└── service
└── toDoList.go使用 protoc 生成存根
protoc -I proto \
--go_out ./pb/todoPb --go_opt paths=source_relative \
--go-grpc_out ./pb/todoPb --go-grpc_opt paths=source_relative \
--grpc-gateway_out ./pb/todoPb --grpc-gateway_opt paths=source_relative \
proto/toDoList.proto
protoc-go-inject-tag -XXX_skip=xorm -input=./pb/todoPb/toDoList.pb.go执行以上 protoc 命令工具,生成一个 *.gw.pb.go 文件。
创建 grpc-gateway 目录,并创建 main.go 文件,创建 gRPC-Gateway 多路复用器。
func main() {
ctx := context.Background()
ctx, cancel := context.WithCancel(ctx)
defer cancel()
mux := runtime.NewServeMux()
opts := []grpc.DialOption{ grpc.WithTransportCredentials(insecure.NewCredentials())}
err := pb.RegisterToDoListHandlerFromEndpoint(ctx, mux, grpcServerEndpoint, opts)
if err != nil {
log.Fatalf("Fail to register gRPC gateway service endpoint: %v", err)
}
if err = http.ListenAndServe(":8080", mux); err != nil {
log.Fatalf("Could not setup HTTP endpoint: %v", err)
}
}启动服务
grpc 服务
go run main.gogRPC-Gateway
go run grpc-gateway/main.gocURL 测试
curl http://127.0.0.1:8080/v1/todolist/select?page=1&count=2响应结果:
{
"todolist": [
{
"id": "1",
"content": "编程写代码",
"datetime": "1632541505",
"created": "1632541505",
"updated": "1632541505"
},
{
"id": "2",
"content": "编程写代码",
"datetime": "1632543373",
"created": "1632543373",
"updated": "1632543373"
}
]
}04总结
本文我们介绍 gRPC-Gateway 如何实现同时支持 gRPC 和 RESTful 风格的 API。
当 HTTP 请求到达 gRPC-Gateway 时,它会将 JSON 数据解析为 protobuf 消息。然后,它使用解析的 protobuf 消息发出正常的 Go gRPC 客户端请求。
Go gRPC 客户端将 protobuf 结构编码为 protobuf 二进制格式,并将其发送到 gRPC 服务器。gRPC 服务器处理请求并以 protobuf 二进制格式返回响应。
Go gRPC 客户端将其解析为 protobuf 消息,并将其返回到 gRPC-Gateway,后者将 protobuf 消息编码为 JSON 并将其返回到原始客户端。
图片来自 gRPC-Gateway 官方文档
云服务器提供商很赞哦!(3)