前言 gRPC-Gateway is a plugin of protoc. It reads a gRPC service definition and generates a reverse-proxy server which translates a RESTful JSON API into gRPC. This server is generated according to custom options in your gRPC definition.(官网 )
下载依赖 1 2 3 go install github.com/grpc-ecosystem/grpc-gateway/v2/protoc-gen-grpc-gateway@latest go install google.golang.org/protobuf/cmd/protoc-gen-go@latest go install google.golang.org/grpc/cmd/protoc-gen-go-grpc@latest
下载Google提供的Protobuf 1 2 3 4 5 mkdir -p google/api cd google/api wget https://raw.githubusercontent.com/googleapis/googleapis/master/google/api/annotations.proto wget https://raw.githubusercontent.com/googleapis/googleapis/master/google/api/http.proto cd ../..
1 2 3 4 + google + api - annotations.proto - http.proto
创建基本的GRPC结构 client/main.go 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 package mainimport ( "context" "fmt" "github.com/feiju12138/grpc/test" "google.golang.org/grpc" ) func main () { listen, _ := grpc.Dial("127.0.0.1:8888" , grpc.WithInsecure()) client := test.NewTestServiceClient(listen) res, _ := client.Test(context.Background(), &test.Req{Message: "1" }) fmt.Println(res.GetMessage()) }
service/main.go 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 package mainimport ( "context" "github.com/feiju12138/grpc/test" "google.golang.org/grpc" "net" ) type TestService struct { test.UnimplementedTestServiceServer } func (*TestService) Test(context context.Context, req *test.Req) (*test.Res, error ) { return &test.Res{Message: req.GetMessage()}, nil } func main () { listen, _ := net.Listen("tcp" , "0.0.0.0:8888" ) server := grpc.NewServer() test.RegisterTestServiceServer(server, &TestService{}) server.Serve(listen) }
test/test.proto 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 syntax = "proto3" ; option go_package="github.com/feiju12138/grpc/test;test" ;package test;message Req { string message = 1 ; } message Res { string message = 1 ; } service TestService { rpc Test(Req) returns (Res) ; }
在Protobuf的service中添加option test/test.proto 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 syntax = "proto3" ; option go_package="github.com/feiju12138/grpc/test;test" ;import "google/api/annotations.proto" ;package test;message Req { string message = 1 ; } message Res { string message = 1 ; } service TestService { rpc Test(Req) returns (Res) { option (google.api.http) = { post:"/api/test" , body:"*" , }; }; }
GRPC生成Go代码
-I ./proto:指定项目根目录的所在路径--go_out ./、--go-grpc_out ./、--grpc-gateway_out .:指定相对于项目根目录的路径./test/test.proto:Protobuf的所在路径
1 2 3 4 5 protoc -I ./ \ --go_out ./ --go_opt paths=source_relative \ --go-grpc_out ./ --go-grpc_opt paths=source_relative \ --grpc-gateway_out ./ --grpc-gateway_opt paths=source_relative \ ./test/test.proto
会在Protobuf文件同级目录下生成test.pb.go、test.pb.gw.go、test_grpc.pb.go文件
在服务端添加对外暴露的代码 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 package mainimport ( "context" "github.com/feiju12138/grpc/test" "github.com/grpc-ecosystem/grpc-gateway/v2/runtime" "google.golang.org/grpc" "net" "net/http" "sync" ) type TestService struct { test.UnimplementedTestServiceServer } func (*TestService) Test(context context.Context, req *test.Req) (*test.Res, error ) { return &test.Res{Message: req.GetMessage() + "0" }, nil } func registerGateway (waitGroup *sync.WaitGroup) { conn, _ := grpc.DialContext(context.Background(), "127.0.0.1:8888" , grpc.WithBlock(), grpc.WithInsecure()) mux := runtime.NewServeMux() gatewayServer := &http.Server{ Handler: mux, Addr: "0.0.0.0:8889" , } gatewayServer.ListenAndServe() test.RegisterTestServiceHandler(context.Background(), mux, conn) waitGroup.Done() } func registerGRPC (waitGroup *sync.WaitGroup) { listen, _ := net.Listen("tcp" , "0.0.0.0:8888" ) server := grpc.NewServer() test.RegisterTestServiceServer(server, &TestService{}) server.Serve(listen) waitGroup.Done() } func main () { waitGroup := sync.WaitGroup{} waitGroup.Add(2 ) go registerGateway(&waitGroup) go registerGRPC(&waitGroup) waitGroup.Wait() }
GRPCGateway配置 处理GET请求 request 1 2 GET http://127.0.0.1:8080/api/test?message=1 Accept : application/json
请求参数映射为字符串 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 syntax = "proto3" ; option go_package="github.com/feiju12138/grpc/test;test" ; import "google/api/annotations.proto" ;package test;message Req { string message = 1 ; } message Res { string message = 1 ; } service TestService { rpc Test(Req) returns (Res) { option(google.api.http) = { get:"/api/test" , }; }; }
请求参数映射为结构体 request 1 2 GET http://127.0.0.1:8080/api/test?message.key=1 Accept : application/json
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 syntax = "proto3" ; option go_package="github.com/feiju12138/grpc/test;test" ; import "google/api/annotations.proto" ;package test;message Message { string key = 1 } message Req { Message message = 1 ; } message Res { string message = 1 ; } service TestService { rpc Test(Req) returns (Res) { option(google.api.http) = { get:"/api/test" , }; }; }
处理POST请求 请求参数映射为字符串 从query获取数据 request 1 2 POST http://127.0.0.1:8080/api/test?message=1 Accept : application/json
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 syntax = "proto3" ; option go_package="github.com/feiju12138/grpc/test;test" ; import "google/api/annotations.proto" ;package test;message Req { string message = 1 ; } message Res { string message = 1 ; } service TestService { rpc Test(Req) returns (Res) { option(google.api.http) = { post:"/api/test" , body:"*" , }; }; }
从body获取数据 request 1 2 3 4 POST http://127.0.0.1:8080/api/test Accept : application/json"1"
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 syntax = "proto3" ; option go_package="github.com/feiju12138/grpc/test;test" ; import "google/api/annotations.proto" ;package test;message Req { string message = 1 ; } message Res { string message = 1 ; } service TestService { rpc Test(Req) returns (Res) { option(google.api.http) = { post:"/api/test" , body:"*" , }; }; }
从path获取数据 request 1 2 POST http://127.0.0.1:8080/api/test/1 Accept : application/json
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 syntax = "proto3" ; option go_package="github.com/feiju12138/grpc/test;test" ; import "google/api/annotations.proto" ;package test;message Req { string message = 1 ; } message Res { string message = 1 ; } service TestService { rpc Test(Req) returns (Res) { option(google.api.http) = { post:"/api/test/{message}" , body:"*" , }; }; }
请求参数映射为结构体 从query获取数据 request 1 2 POST http://127.0.0.1:8080/api/test?message.key=1 Accept : application/json
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 syntax = "proto3" ; option go_package="github.com/feiju12138/grpc/test;test" ; import "google/api/annotations.proto" ;package test;message Message { string key = 1 } message Req { Message message = 1 ; } message Res { string message = 1 ; } service TestService { rpc Test(Req) returns (Res) { option(google.api.http) = { post:"/api/test" , body:"message" , }; }; }
从body获取数据 request 1 2 3 4 POST http://127.0.0.1:8080/api/test Accept : application/json{"key": "value"}
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 syntax = "proto3" ; option go_package="github.com/feiju12138/grpc/test;test" ; import "google/api/annotations.proto" ;package test;message Message { string key = 1 } message Req { Message message = 1 ; } message Res { string message = 1 ; } service TestService { rpc Test(Req) returns (Res) { option(google.api.http) = { post:"/api/test" , body:"message" , }; }; }
完成 参考文献 Github——go圈里最会写js的奇淼