新聞中心
01介紹
當(dāng)我們需要提供 gRPC 服務(wù)的 RESTful API 時(shí),可以先創(chuàng)建一個(gè) gRPC 客戶端服務(wù),在 gRPC 客戶端服務(wù)編寫 RESTful API,接收到 HTTP 請(qǐng)求時(shí),通過(guò) gRPC 客戶端服務(wù)調(diào)用 gRPC 服務(wù)端服務(wù)的方法。

在成都做網(wǎng)站、網(wǎng)站建設(shè)中從網(wǎng)站色彩、結(jié)構(gòu)布局、欄目設(shè)置、關(guān)鍵詞群組等細(xì)微處著手,突出企業(yè)的產(chǎn)品/服務(wù)/品牌,幫助企業(yè)鎖定精準(zhǔn)用戶,提高在線咨詢和轉(zhuǎn)化,使成都網(wǎng)站營(yíng)銷成為有效果、有回報(bào)的無(wú)錫營(yíng)銷推廣。創(chuàng)新互聯(lián)建站專業(yè)成都網(wǎng)站建設(shè)十多年了,客戶滿意度97.8%,歡迎成都創(chuàng)新互聯(lián)客戶聯(lián)系。
相信讀者朋友們也意識(shí)到,僅僅為了提供 RESTful API 而編寫一個(gè) gRPC 客戶端服務(wù),顯然有些小題大做。
在不借助 gRPC 客戶端服務(wù)的前提下,gRPC 服務(wù)端服務(wù)怎么同時(shí)支持 gRPC 和 HTTP 客戶端調(diào)用?今天我們介紹一個(gè) protoc 插件 gRPC-Gateway。
02gRPC-Gateway
gRPC-Gateway 是 protoc 的一個(gè)插件。它讀取 gRPC 服務(wù)定義并生成一個(gè)反向代理服務(wù)器,該服務(wù)器將 RESTful JSON API 轉(zhuǎn)換為 gRPC。此服務(wù)器是根據(jù) gRPC 定義中的自定義選項(xiàng)生成的。
gRPC-Gateway 可幫助您同時(shí)以 gRPC 和 RESTful 風(fēng)格提供 API。
在我們開始編碼之前,需要一些先決條件。
首先,我們需要先搭建一個(gè) Go 環(huán)境。
使用 go get 工具下載一些依賴包。
使用 go mod init 工具創(chuàng)建一個(gè) 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-grpc
03gRPC-Gateway 實(shí)戰(zhàn)
在完成以上先決條件后,我們創(chuàng)建一個(gè) gRPC 服務(wù)端服務(wù),本文我們創(chuàng)建一個(gè) ToDoList gRPC 服務(wù)。在創(chuàng)建 gRPC 服務(wù)之前,我們使用 protocol buffers 創(chuàng)建一個(gè) proto 文件。
創(chuàng)建 proto 文件
...
service ToDoList {
rpc CreateToDoList (ToDoListDetail) returns (CreateToDoListResult) {}
rpc ReadToDoList (ToDoListPage) returns (ReadToDoListByPage) {}
}
...
生成 gRPC 服務(wù)端存根
使用 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
執(zhí)行上面 protoc 命令工具,生成一個(gè) *.pb.go 文件和一個(gè) *_grpc.pb.go 文件。
編寫剩余 Go 代碼
創(chuàng)建 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 選項(xiàng)
gRPC-Gateway 使用 google.api.http 選項(xiàng)定義 gRPC 服務(wù)如何映射到 JSON 請(qǐng)求和響應(yīng),使用 protoc 時(shí),每個(gè) RPC 必須使用 google.api.http 選項(xiàng)定義 HTTP 方法和路徑。
因此,我們需要將 google/api/http.proto 導(dǎo)入添加到 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"
};
}
}
...
關(guān)于 HTTP 和 gRPC 映射的更多內(nèi)容,可以參閱 Google API 文檔。
生成 gRPC-Gateway 存根
現(xiàn)在,我們已將 gRPC-Gateway 選項(xiàng)添加到 proto 文件中,我們需要使用 gRPC-Gateway 生成器來(lái)生成存根。
在使用 protoc 生成存根之前,我們需要將一些依賴項(xiàng)復(fù)制到 proto 文件目錄中。將 googleapis 的子集從官方存儲(chǔ)庫(kù)下載并復(fù)制到本地 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
執(zhí)行以上 protoc 命令工具,生成一個(gè) *.gw.pb.go 文件。
創(chuàng)建 grpc-gateway 目錄,并創(chuàng)建 main.go 文件,創(chuàng)建 gRPC-Gateway 多路復(fù)用器。
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)
}
}啟動(dòng)服務(wù)
grpc 服務(wù)
go run main.go
gRPC-Gateway
go run grpc-gateway/main.go
cURL 測(cè)試
curl http://127.0.0.1:8080/v1/todolist/select?page=1&count=2
響應(yīng)結(jié)果:
{
"todolist": [
{
"id": "1",
"content": "編程寫代碼",
"datetime": "1632541505",
"created": "1632541505",
"updated": "1632541505"
},
{
"id": "2",
"content": "編程寫代碼",
"datetime": "1632543373",
"created": "1632543373",
"updated": "1632543373"
}
]
}04總結(jié)
本文我們介紹 gRPC-Gateway 如何實(shí)現(xiàn)同時(shí)支持 gRPC 和 RESTful 風(fēng)格的 API。
當(dāng) HTTP 請(qǐng)求到達(dá) gRPC-Gateway 時(shí),它會(huì)將 JSON 數(shù)據(jù)解析為 protobuf 消息。然后,它使用解析的 protobuf 消息發(fā)出正常的 Go gRPC 客戶端請(qǐng)求。
Go gRPC 客戶端將 protobuf 結(jié)構(gòu)編碼為 protobuf 二進(jìn)制格式,并將其發(fā)送到 gRPC 服務(wù)器。gRPC 服務(wù)器處理請(qǐng)求并以 protobuf 二進(jìn)制格式返回響應(yīng)。
Go gRPC 客戶端將其解析為 protobuf 消息,并將其返回到 gRPC-Gateway,后者將 protobuf 消息編碼為 JSON 并將其返回到原始客戶端。
當(dāng)前名稱:Golang語(yǔ)言gRPC服務(wù)怎么同時(shí)支持gRPC和HTTP客戶端調(diào)用?
URL鏈接:http://fisionsoft.com.cn/article/coghsde.html


咨詢
建站咨詢
