目标:简单微服务+ grpc-ecosystem/grpc-gateway;
https://github.com/grpc-ecosystem/grpc-gateway
https://grpc-ecosystem.github.io/grpc-gateway/
grpc-gateway 是 google bufers 协议的 编译器 protoc 的 一个插件。
它 读取 protobuf 服务 定义文件 并且 生成一个反向代理 服务,这个反向代理服务
负责 转换 RESTful HTTP API 到 gRPC.
grpc-gateway 将帮助你 发布 以 gRPC 和 RESTful 两种方式 同时发布 你的 APIS
注意:
如果 你不想 因为使用了 grpc-gateway 去 修改 proto 文件, 替代地 你可以使用 一个 扩展的 服务配置文件。
gRPC 错误码 到 HTTP 的响应状态码。
HTTP 请求的IP 被 添加为 X-Forwarded-For (grpc 请求头)
HTTP 请求HOST 被添加为 X-Forwarded-Host (grpc 请求头)
HTTP 请求 Authorization 被添加为 authorization (grpc 请求头)
剩余的 永久性的 http 头 里边字段 被 加上 grpcgateway- 前缀,添加到 grpc 头中。
HTTP 头 以 Grpc-Metadata-’ 开始的 被映射到 gRPC metadata (前缀为 grpcgateway-)
While configurable, the default {un,}marshaling uses jsonpb with OrigName: true.
但在实际使用过程中,也在grpc-gateway里发现了一些问题,比如:
1,灵活性不够,如果有一些比较特殊的需求,在grpc-gateway中能扩展的余地不大;
2,严重依赖protocol buffer,而且必须是protobuf 3;
3,即使grpc服务的接口不变,只是修改HTTP接口定义,也必须重新生成代码,也就必须重新部署,重启服务;
4,只支持JSON格式的输入,不支持传统的kv格式的参数;
5,只支持grpc,嗯。。好吧,这不算问题,但thrift也很普及,是不是?
6,grpc-gateway在错误处理等方面都不够成熟,而且开发者似乎也不是很活跃。。。
使用到的包: protobuf + grpc + grpc-gateway
目录如下:
proto/user.proto 文件内容如下:
syntax = "proto3";
package user;
//引入google api实现http转rpc
import "google/api/annotations.proto";
service userInfoService {
rpc GetUserInfo(UserRequest) returns (UserResponse){
option (google.api.http) = {
post: "/v1/userInfo"
body: "*"
};
}
}
//定义客户端请求的数据格式
//message 对应 生成的代码中的struct
message UserRequest{
// [修饰符] 类型 字段名 = 标识符
string name = 1;
}
message UserResponse{
int32 id=1;
string name=2;
int32 age =3;
repeated string title = 4; // 可变数组,即 slice 类型
}
生成user.pb.go
protoc -I/usr/local/include -I. \
-I$GOPATH/src \
-I$GOPATH/pkg/mod/github.com/grpc-ecosystem/grpc-gateway\@v1.12.1/third_party/googleapis/ \
--go_out=plugins=grpc:. \
proto/user.proto
生成user.pb.gw.go
protoc -I/usr/local/include -I. \
-I$GOPATH/src \
-I$GOPATH/pkg/mod/github.com/grpc-ecosystem/grpc-gateway\@v1.12.1/third_party/googleapis/ \
--grpc-gateway_out=logtostderr=true:. \
proto/user.proto
server.go 代码如下:
package main
import (
"context"
"fmt"
"google.golang.org/grpc"
proto "grpc_gateway_service/proto"
"log"
"net"
)
//定义服务端 实现 约定的接口
type UserInfoService struct{}
var u = UserInfoService{}
//实现 interface
func (s *UserInfoService) GetUserInfo(ctx context.Context, req *proto.UserRequest) (resp *proto.UserResponse, err error) {
name := req.Name
resp = &proto.UserResponse{}
if name == "liang" {
resp = &proto.UserResponse{
Id: 1568,
Name: name,
Age: 25,
Title: []string{"PHPer", "Gopher"},
}
}
err = nil
return resp, err
}
func main() {
port := ":6666"
l, err := net.Listen("tcp", port)
if err != nil {
log.Fatalf("listen error: %v\n", err)
}
fmt.Printf("listen %s\n", port)
s := grpc.NewServer()
// 将 UserInfoService 注册到 gRPC
// 注意第二个参数 UserInfoServiceServer 是接口类型的变量
// 需要取地址传参
proto.RegisterUserInfoServiceServer(s, &u)
s.Serve(l)
}
gateway/main.go
package main
import (
"context"
"flag"
"github.com/golang/glog"
"github.com/grpc-ecosystem/grpc-gateway/runtime"
"google.golang.org/grpc"
//多个服务引入多个包
proto "grpc_gateway_service/proto"
"net/http"
)
var (
// command-line options:
// gRPC server endpoint
grpcServerEndpoint = flag.String("grpc-server-endpoint", "localhost:6666", "gRPC server endpoint")
)
func run() error {
ctx := context.Background()
ctx, cancel := context.WithCancel(ctx)
defer cancel()
// Register gRPC server endpoint
// Note: Make sure the gRPC server is running properly and accessible
mux := runtime.NewServeMux()
opts := []grpc.DialOption{grpc.WithInsecure()}
//多个服务注册多次即可
err := proto.RegisterUserInfoServiceHandlerFromEndpoint(ctx, mux, *grpcServerEndpoint, opts)
if err != nil {
return err
}
// Start HTTP server (and proxy calls to gRPC server endpoint)
return http.ListenAndServe(":8081", mux)
}
func main() {
flag.Parse()
defer glog.Flush()
if err := run(); err != nil {
glog.Fatal(err)
}
}
运行 server.go ; gateway/main.go;
终端执行:
bogon:grpc_gateway_service zhaozhiliang$ curl -H "Content-Type:application/json" -X POST --data '{"name":"liang"}' http://127.0.0.1:8081/v1/userInfo
{"id":1568,"name":"liang","age":25,"title":["PHPer","Gopher"]}bogon:grpc_gateway_service zhaozhiliang$
bogon:grpc_gateway_service zhaozhiliang$ curl -H "Content-Type:application/json" -X POST --data '{"name":"liang2"}' http://127.0.0.1:8081/v1/userInfo
{}bogon:grpc_gateway_service zhaozhiliang$
go.mod 内容如下:
module grpc_gateway_service
go 1.13
require (
github.com/golang/protobuf v1.3.2
github.com/grpc-ecosystem/grpc-gateway v1.12.1
google.golang.org/genproto v0.0.0-20191230161307-f3c370f40bfb
google.golang.org/grpc v1.24.0
gopkg.in/yaml.v2 v2.2.7 // indirect
)