实现了一个协议转换的网关,对应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!"}'
复制代码
近期评论