grpc-ecosystem/grpc-gateway 基本概念和原理 / 实现网关和微服务

目标:简单微服务+ 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-ecosystem/grpc-gateway 基本概念和原理 / 实现网关和微服务_第1张图片

注意:

如果 你不想 因为使用了 grpc-gateway  去 修改 proto 文件, 替代地 你可以使用  一个 扩展的  服务配置文件。

 gRPC  到 HTTP 映射

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

目录如下:

grpc-ecosystem/grpc-gateway 基本概念和原理 / 实现网关和微服务_第2张图片

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
)

 

 

 

 

 

 

你可能感兴趣的:(go语言)