文章目录

不积跬步无以至千里

记录精彩的程序人生

Grpc-Gateway:Grpc转换为http协议对外提供服务 有更新!

  aluaa

使用grpc的优点很多,二进制的数据可以加快传输速度,基于http2的多路复用可以减少服务之间的连接次数,和函数一样的调用方式也有效的提升了开发效率。

不过使用grpc也会面临一个问题,我们的微服务对外一定是要提供Restful接口的,如果内部调用使用grpc,在某些情况下要同时提供一个功能的两套API接口,这样就不仅降低了开发效率,也增加了调试的复杂度。于是就想着有没有一个转换机制,让Restful和gprc可以相互转化。

一、grpc-gateway介绍

grpc-gateway是protoc的一个插件 。它读取Grpc服务定义,并生成反向代理服务器,将RESTful JSON API请求转换为Grpc的方式调用。主要是根据 google.api.http定义中思想完成的,一下就是grpc-gateway结构图:
如图:

二、grpc-gateway环境准备

go get -u github.com/grpc-ecosystem/grpc-gateway/protoc-gen-grpc-gateway
go get -u github.com/grpc-ecosystem/grpc-gateway/protoc-gen-swagger
go get -u github.com/golang/protobuf/protoc-gen-go
cd  $GOPATH/src/ 
mkdir -p grpc-gateway-demo/gateway 
cd grpc-gateway-demo/gateway 
vim gateway.proto
syntax = "proto3";
package gateway;

import "google/api/annotations.proto";

message StringMessage {
    string value = 1;
}

service Gateway {
   rpc Echo(StringMessage) returns (StringMessage) {
       option (google.api.http) = {
           post: "/v1/example/echo"
           body: "*"
       };
   }
}

和之前的proto文件比较,新的文件增了

import "google/api/annotations.proto";

option (google.api.http) = {
post: "/v1/example/echo"
body: "*"

这里增加了对http的扩展配置。

生成grpc的go的服务server文件

protoc --proto_path=../ -I/usr/local/include -I. -I$GOPATH/src -I$GOPATH/src/github.com/grpc-ecosystem/grpc-gateway/third_party/googleapis --go_out=plugins=grpc:. gateway.proto

这里生成了gateway.pb.go文件,gateway.pb.go是server服务需要的

生成gateway需要的go文件

protoc --proto_path=../ -I/usr/local/include -I. -I$GOPATH/src -I$GOPATH/src/github.com/grpc-ecosystem/grpc-gateway/third_party/googleapis --grpc-gateway_out=logtostderr=true:. gateway.proto

这里生成了gateway.pb.gw.go文件。这个文件就是gateway用来的协议文件,用来做grpc和http的协议转换。

三、编写grpc-gateway服务

vim grpc_service.go
package main

import (
        "log"
        "net"

        "google.golang.org/grpc"
        "golang.org/x/net/context"

        pb "grpc-gateway-demo/gateway"
)

const (
        PORT = ":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", PORT)

        if err != nil {
                log.Fatalf("failed to listen: %v", err)
        }

        s := grpc.NewServer()
        pb.RegisterGatewayServer(s, &server{})
        log.Println("rpc服务已经开启")
        s.Serve(lis)
}

运行grpc服务端:

go build grpc_service.go
./grpc_service

编写gateway服务:

vim grpc_gateway.go
package main

import (
        "log"
        "flag"
        "net/http"

        "github.com/golang/glog"
        "github.com/grpc-ecosystem/grpc-gateway/runtime"
        "golang.org/x/net/context"
        "google.golang.org/grpc"

        gw "grpc-gateway-demo/gateway"
)

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.RegisterGatewayHandlerFromEndpoint(ctx, mux, *echoEndpoint, opts)
        if err != nil {
                return err
        }

        log.Println("服务开启")
        return http.ListenAndServe(":8080", mux)
}

func main() {
        flag.Parse()
        defer glog.Flush()

        if err := run(); err != nil {
                glog.Fatal(err)
        }
}

首先echoEndpoint存储了需要连接的server信息,然后将这些信息和新建的server用gw.go中的RegisterGatewayHandlerFromEndpoint进行一个注册和绑定,这时低层就会连接echoEndpoint提供的远程server地址,这样gateway就作为客户端和远程server建立了连接,之后用http启动新建的server,gateway就作为服务器端对外提供http的服务了。

运行网关程序

go build grpc_gateway.go
./grpc_gateway

使用http的方式调用网关:

curl -X POST -k http://localhost:8080/v1/example/echo -d '{"value":" world"}'
{"value":"Hello  world"}

四、流程总结

流程如下:curl用post向grpc_gateway发送请求,grpc_gateway作为proxy将请求转化一下通过grpc转发给grpc_service,grpc_service通过grpc返回结果,grpc_gateway收到结果后,转化成json返回给前端。

这样,就通过grpc-gateway完成了从http json到内部grpc的转化过程。

validate