使用Google的protobuf,将REST端点映射到gRPC服务器
介绍一下,您可以使用Google提供的googleapis1源代码来支持REST和gRPC两种协议。
在需要使用HTTP/1.1进行通信的情况下,了解这一点会很方便。就我个人而言,在将请求转发到gRPC服务器时,我将其实现为ALB的目标组的健康检查端点。
我当时使用了 envoy 来搭建代理,但这一次我决定使用 grpc-gateway。
首先准备 gRPC 服务器。
由于我需要一个能快速运行的实例,所以借用了 grpc-go 的 helloworld。
git clone https://github.com/grpc/grpc-go
# 以降も基本的にこのディレクトリで作業する
cd grpc-go/examples/helloworld/
# gRPCサーバー起動
go run greeter_server/main.go
# クライアントコード実行で動作確認
go run greeter_client/main.go
2020/09/14 23:02:48 Greeting: Hello world
.proto 文件的内容如下所示。
syntax = "proto3";
option go_package = "google.golang.org/grpc/examples/helloworld/helloworld";
option java_multiple_files = true;
option java_package = "io.grpc.examples.helloworld";
option java_outer_classname = "HelloWorldProto";
package helloworld;
// The greeting service definition.
service Greeter {
// Sends a greeting
rpc SayHello (HelloRequest) returns (HelloReply) {}
}
// The request message containing the user's name.
message HelloRequest {
string name = 1;
}
// The response message containing the greetings
message HelloReply {
string message = 1;
}
REST API 映射
你好世界.proto已修正
导入 annotations.proto,在 rpc 的定义中添加 option (google.api.http) {…}。
syntax = "proto3";
option go_package = "google.golang.org/grpc/examples/helloworld/helloworld";
option java_multiple_files = true;
option java_package = "io.grpc.examples.helloworld";
option java_outer_classname = "HelloWorldProto";
// 追記
import "google/api/annotations.proto";
package helloworld;
// The greeting service definition.
service Greeter {
// Sends a greeting
rpc SayHello (HelloRequest) returns (HelloReply) {
// 追記
option (google.api.http) = {
get: "/say_hello"
};
}
}
// The request message containing the user's name.
message HelloRequest {
string name = 1;
}
// The response message containing the greetings
message HelloReply {
string message = 1;
}
获取 googleapis 的源代码
go get -u github.com/googleapis/googleapis
只需要在编译时进行引用,所以甚至可以使用 git clone 之类的方式,都可以。
根据修改后的 protobuf 进行自动生成。
安装编译器插件
go get -u github.com/grpc-ecosystem/grpc-gateway/protoc-gen-grpc-gateway
go get -u github.com/golang/protobuf/protoc-gen-go
gRPC Server专用
这时候,在 protoc 命令中添加 -I 选项,以便能够引用到 google/api/annotations.proto。另外,由于现有的 helloworld_grpc.pb.go 和生成的客户端代码重复了,所以很抱歉,这次需要删除它们。
protoc \
-I. -I$GOPATH/src/github.com/googleapis/googleapis \
--go_out=plugins=grpc:. --go_opt=paths=source_relative \
helloworld/helloworld.proto
// 申し訳ないが消す
rm helloworld/helloworld_grpc.pb.go
适用于代理服务器的
使用grpc-gateway的编译器插件进行类似的自动生成。
protoc -I. -I$GOPATH/src/github.com/googleapis/googleapis \
--grpc-gateway_out=logtostderr=true,paths=source_relative:. \
helloworld/helloworld.proto
修改 gRPC 服务器的实现。
根据生成的 helloworld.pb.go 文件,对服务器的实现进行修改。
package main
import (
"context"
"log"
"net"
"google.golang.org/grpc"
pb "google.golang.org/grpc/examples/helloworld/helloworld"
)
const (
port = ":50051"
)
// 追記
type server struct {}
// 修正: ポインタレシーバに修正
func (s *server) SayHello(ctx context.Context, in *pb.HelloRequest) (*pb.HelloReply, error) {
log.Printf("Received: %v", in.GetName())
return &pb.HelloReply{Message: "Hello " + in.GetName()}, nil
}
func main() {
lis, err := net.Listen("tcp", port)
if err != nil {
log.Fatalf("failed to listen: %v", err)
}
s := grpc.NewServer()
// 修正: server を代入
pb.RegisterGreeterServer(s, &server{})
if err := s.Serve(lis); err != nil {
log.Fatalf("failed to serve: %v", err)
}
}
代理服务器的实施
package main
import (
"flag"
"net/http"
"github.com/golang/glog"
"github.com/grpc-ecosystem/grpc-gateway/runtime"
"golang.org/x/net/context"
"google.golang.org/grpc"
gw "google.golang.org/grpc/examples/helloworld/helloworld"
)
var (
tasklistEndpoint = flag.String("tasklist_endpoint", "localhost:50051", "endpoint of YourService")
)
func run() error {
ctx := context.Background()
ctx, cancel := context.WithCancel(ctx)
defer cancel()
mux := runtime.NewServeMux()
opts := []grpc.DialOption{grpc.WithInsecure()}
err := gw.RegisterGreeterHandlerFromEndpoint(ctx, mux, *tasklistEndpoint, opts)
if err != nil {
return err
}
return http.ListenAndServe(":8080", mux)
}
func main() {
flag.Parse()
defer glog.Flush()
if err := run(); err != nil {
glog.Fatal(err)
}
}
验证动作

如果你对设置POST或请求头也感兴趣,可以点击以下链接了解更多信息:https://grpc-ecosystem.github.io/grpc-gateway/
仅提供一种中文选择:
参考一下。
-
- https://github.com/grpc-ecosystem/grpc-gateway
-
- https://grpc.io/docs/languages/go/quickstart
-
- https://github.com/grpc/grpc-go
-
- https://budougumi0617.github.io/2018/02/03/grpc-gateway-for-rest-api/
-
- https://qiita.com/ryu3/items/b2882d4f45c7f8485030
- https://grpc-ecosystem.github.io/grpc-gateway/
或者,https://github.com/grpc-ecosystem/grpc-gateway/tree/master/third_party/googleapis ↩