golang gRPC转换HTTP对外提供服务
实现了一个协议转换的网关,对应github上的项目github.com/grpc-ecosys… ,这个网关负责接收客户端请求,然后决定直接转发给grpc服务还是转给http服务,当然,http服务也需要请求grpc服务获取响应,然后转为json响应给客户端。结构如图:
安装工具
$ go get -u github.com/grpc-ecosystem/grpc-gateway/protoc-gen-grpc-gateway复制代码
目录结构
├─grpcgateway │ ├─echohttp │ │ ├─client │ │ │ main.go │ │ │ │ │ ├─server │ │ │ main.go │ │ │ │ │ └─server_http │ │ main.go │ │ │ └─protos │ ├─echo │ │ service.pb.go │ │ service.pb.gw.go │ │ service.proto │ │ service_grpc.pb.go │ │ │ └─google │ └─api │ annotations.pb.go │ annotations.proto │ http.pb.go │ http.proto复制代码
demo
$ cd protos复制代码
1.annotations.proto 和 http.proto 从 github.com/googleapis/… 拷贝到本地
2.echo/service.proto:
syntax = "proto3"; option go_package = "./echo"; package echo; import "google/api/annotations.proto"; service EchoService { rpc Echo(EchoMessage) returns (EchoMessage) { option (google.api.http) = { post: "/v1/echo" body: "*" }; } } message EchoMessage { string value = 1; }复制代码
3.编译proto
编译google.api
$ protoc -I . --go_out=paths=source_relative:. --go_opt=Mgoogle/protobuf/descriptor.proto=github.com/golang/protobuf/protoc-gen-go/descriptor:. google/api/*.proto复制代码
编译echo.proto
$ protoc -I . --go_out=. --go_opt=Mgoogle/api/annotations.proto=./google/api:. --go-grpc_out=. --go-grpc_opt=Mgoogle/api/annotations.proto=./google/api:. echo/*.proto复制代码
编译echo.proto gateway
$ protoc --grpc-gateway_out=logtostderr=true:. echo/*.proto复制代码
4.实现服务端和客户端 server/main.go
package main import ( "fmt" "net" pb "zpool/grpcgateway/protos/echo" "golang.org/x/net/context" "google.golang.org/grpc" "google.golang.org/grpc/grpclog" ) const ( Address = "127.0.0.1:50052" ) type echoService struct { pb.UnimplementedEchoServiceServer } func (*echoService) Echo(ctx context.Context, in *pb.EchoMessage) (*pb.EchoMessage, error) { return &pb.EchoMessage{ Value: in.Value, }, nil } func main() { listen, err := net.Listen("tcp", Address) if err != nil { grpclog.Fatalf("Failed to listen: %v", err) } // 实例化grpc Server s := grpc.NewServer() // 注册echoService pb.RegisterEchoServiceServer(s, &echoService{}) fmt.Println("Listen on " + Address) s.Serve(listen) }复制代码
client/main.go
package main import ( "fmt" "golang.org/x/net/context" "google.golang.org/grpc" "google.golang.org/grpc/grpclog" pb "zpool/grpcgateway/protos/echo" ) const ( Address = "127.0.0.1:50052" ) func main() { // 连接 conn, err := grpc.Dial(Address, grpc.WithInsecure()) if err != nil { grpclog.Fatalln(err) } defer conn.Close() // 初始化客户端 c := pb.NewEchoServiceClient(conn) // 调用方法 req := &pb.EchoMessage{Value: "gRPC"} res, err := c.Echo(context.Background(), req) if err != nil { grpclog.Fatalln(err) } fmt.Println(res.Value) }复制代码
5.server_http/main.go
package main import ( "fmt" "net/http" "github.com/grpc-ecosystem/grpc-gateway/runtime" "golang.org/x/net/context" "google.golang.org/grpc" "google.golang.org/grpc/grpclog" gw "zpool/grpcgateway/protos/echo" ) func main() { ctx := context.Background() ctx, cancel := context.WithCancel(ctx) defer cancel() // grpc服务地址 endpoint := "127.0.0.1:50052" mux := runtime.NewServeMux() opts := []grpc.DialOption{grpc.WithInsecure()} // HTTP转grpc err := gw.RegisterEchoServiceHandlerFromEndpoint(ctx, mux, endpoint, opts) if err != nil { grpclog.Fatalf("Register handler err:%v\n", err) } fmt.Println("HTTP Listen on 8080") http.ListenAndServe(":8080", mux) }复制代码
6.Test
grpc请求:
go run server/main.go go run client/main.go复制代码
http请求:
go run server/main.go go run server_http/main.go curl -X POST -k http://localhost:8080/v1/echo -d '{"value": "gRPC-HTTP is working!"}'
作者:xc_oo
链接:https://juejin.cn/post/7025896168018149412