grpc-gateway是protoc的一个插件。它读取gRPC服务定义,并生成一个反向代理服务器,将RESTful JSON API转换为gRPC。此服务器是根据gRPC定义中的自定义选项生成的。
安装
安装插件
go get \
github.com/grpc-ecosystem/grpc-gateway/v2/protoc-gen-grpc-gateway \
github.com/grpc-ecosystem/grpc-gateway/v2/protoc-gen-openapiv2 \
google.golang.org/protobuf/cmd/protoc-gen-go \
google.golang.org/grpc/cmd/protoc-gen-go-grpc
下载需要使用到的proto
google/protobuf下载参考https://www.yuque.com/jw-go/mqm3eb/gy8npv
google/api 下载地址https://github.com/googleapis/googleapis
文件相互依赖,一次性下载后比较省心
lxdeMacBook-Pro-2:src lx$ pwd
/Users/lx/gopath/src
lxdeMacBook-Pro-2:src lx$ tree google/
google/
├── api
│ ├── BUILD.bazel
│ ├── README.md
│ ├── annotations.proto
│ ├── auth.proto
│ ├── backend.proto
│ ├── billing.proto
│ ├── client.proto
│ ├── config_change.proto
│ ├── consumer.proto
│ ├── context.proto
│ ├── control.proto
│ ├── distribution.proto
│ ├── documentation.proto
│ ├── endpoint.proto
│ ├── error_reason.proto
│ ├── expr
│ │ ├── BUILD.bazel
│ │ ├── cel.yaml
│ │ ├── v1alpha1
│ │ │ ├── BUILD.bazel
│ │ │ ├── checked.proto
│ │ │ ├── conformance_service.proto
│ │ │ ├── eval.proto
│ │ │ ├── explain.proto
│ │ │ ├── syntax.proto
│ │ │ └── value.proto
│ │ └── v1beta1
│ │ ├── BUILD.bazel
│ │ ├── decl.proto
│ │ ├── eval.proto
│ │ ├── expr.proto
│ │ ├── source.proto
│ │ └── value.proto
│ ├── field_behavior.proto
│ ├── http.proto
│ ├── httpbody.proto
│ ├── label.proto
│ ├── launch_stage.proto
│ ├── log.proto
│ ├── logging.proto
│ ├── metric.proto
│ ├── monitored_resource.proto
│ ├── monitoring.proto
│ ├── quota.proto
│ ├── resource.proto
│ ├── service.proto
│ ├── serviceconfig.yaml
│ ├── servicecontrol
│ │ ├── BUILD.bazel
│ │ ├── README.md
│ │ └── v1
│ │ ├── BUILD.bazel
│ │ ├── check_error.proto
│ │ ├── distribution.proto
│ │ ├── http_request.proto
│ │ ├── log_entry.proto
│ │ ├── metric_value.proto
│ │ ├── operation.proto
│ │ ├── quota_controller.proto
│ │ ├── service_controller.proto
│ │ ├── servicecontrol.yaml
│ │ └── servicecontrol_gapic.yaml
│ ├── servicemanagement
│ │ ├── BUILD.bazel
│ │ ├── README.md
│ │ └── v1
│ │ ├── BUILD.bazel
│ │ ├── resources.proto
│ │ ├── servicemanagement_gapic.legacy.yaml
│ │ ├── servicemanagement_gapic.yaml
│ │ ├── servicemanagement_grpc_service_config.json
│ │ ├── servicemanagement_v1.yaml
│ │ └── servicemanager.proto
│ ├── source_info.proto
│ ├── system_parameter.proto
│ └── usage.proto
└── protobuf
├── any.proto
├── api.proto
├── compiler
│ └── plugin.proto
├── descriptor.proto
├── duration.proto
├── empty.proto
├── field_mask.proto
├── source_context.proto
├── struct.proto
├── timestamp.proto
├── type.proto
└── wrappers.proto
跑通流程
1.准备proto文件
syntax = "proto3";
package protobuf;
import "google/api/annotations.proto";
option go_package = "protobuf;protobuf";
message StringMessage{
string value = 1;
}
service EchoService{
rpc Echo(StringMessage) returns (StringMessage){
option (google.api.http) = {
post: "/v1/example/echo"
};
}
}
2.生成grpc存根
protoc --proto_path=/Users/lx/gopath/src --proto_path=. \
--go_out=plugins=grpc,paths=source_relative:. \
test.proto
3.生成代理文件
protoc --proto_path=/Users/lx/gopath/src --proto_path=. \
--grpc-gateway_out . \
--grpc-gateway_opt logtostderr=true \
--grpc-gateway_opt paths=source_relative \
test.proto
4.service端
package main
import (
"log"
"net"
pb "commons/grpc/protobuf"
"golang.org/x/net/context"
"google.golang.org/grpc"
)
const (
RPCPORT = ":9192"
)
type server struct{}
func (s *server) Echo(ctx context.Context, in *pb.StringMessage) (*pb.StringMessage, error) {
log.Println("request: ", in.Value)
return &pb.StringMessage{Value: "Hello " + in.Value}, nil
}
func main() {
lis, err := net.Listen("tcp", RPCPORT)
if err != nil {
log.Fatalf("failed to listen: %v", err)
}
s := grpc.NewServer()
pb.RegisterEchoServiceServer(s, &server{})
log.Println("rpc服务已经开启")
s.Serve(lis)
}
5.gateway
package main
import (
"context"
"flag"
"log"
"net/http"
gw "commons/grpc/protobuf"
"github.com/grpc-ecosystem/grpc-gateway/v2/runtime"
"google.golang.org/grpc"
)
var (
echoEndpoint = flag.String("echo_endpoint", "localhost:9192", "endpoint of Gateway")
)
func run() error {
ctx := context.Background()
ctx, cancel := context.WithCancel(ctx)
defer cancel()
mux := runtime.NewServeMux()
opts := []grpc.DialOption{grpc.WithInsecure()}
err := gw.RegisterEchoServiceHandlerFromEndpoint(ctx, mux, *echoEndpoint, opts)
if err != nil {
return err
}
log.Println("服务开启")
return http.ListenAndServe(":8080", mux)
}
func main() {
flag.Parse()
if err := run(); err != nil {
log.Fatal(err)
}
}
- 测试
- 404
- ok
- methmod not allowed