不积跬步无以至千里

记录精彩的程序人生

  • 首页
  • Java
  • Golang
  • PHP
  • Python
  • Nodejs
  • Lua
  • Docker
  • DevOps
  • 文章归档
  • 默认分类
  • 关于
  • 标签

  • 搜索
PostgreSQL hbase 时间同步 nexus 开机启动 nexus, 开机启动 jenkins安装配置 gitlab安装配置 gitlab安装 文件系统 fastdfs gcc切换 gcc升级 mysql8 交换空间 虚拟内存 tcp thrift lua tag test VPN SoftEtherVPN homebrew asm spring tomcat maven jdk ios mac 图案字符 figlet mysql半同步复制 mysql主从同步 一主多从 一主一从 主从同步 反向代理 密码重置 test 虚拟机扩容 swap 虚拟空间 docker ldocker grpc-gateway protobuf 微服务 go grp GRPC 授权登录 OAuth2.0 SOA supervisord supervisor RPC CentOS rabbitmq 环境变量 php-fpm php.ini error php7 lnmp 编译安装 mysql nginx linux java php python redis 字符串操作 mysql5.7 Solo

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

发表于 2019-05-03 | 分类于 默认分类 | 0 | 阅读次数 4944

使用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的转化过程。

php学习心得
生命是用来燃烧的
  • 文章目录
  • 站点概览
ken

ken

记录精彩的程序人生

498 日志
9 分类
77 标签
RSS
Creative Commons
Links
  • 酷壳
0%
© 2010 — 2025 ken
由 Halo 强力驱动
鄂ICP备18013899号-1