• gRPC学习之五:gRPC-Gateway实战


    欢迎访问我的GitHub

    https://github.com/zq2599/blog_demos

    内容:所有原创文章分类汇总及配套源码,涉及Java、Docker、Kubernetes、DevOPS等;

    gRPC学习系列文章链接

    1. 在CentOS7部署和设置GO
    2. GO的gRPC开发环境准备
    3. 初试GO版gRPC开发
    4. 实战四类服务方法
    5. gRPC-Gateway实战
    6. gRPC-Gateway集成swagger

    本篇概览

    • 本文《gRPC学习》系列的第五篇,gRPC常用于服务端之间的相互调用,如果想把服务暴露给前端,虽然动手修改服务端也能实现,但似乎增加了不少工作量,此时还可以选择gRPC-Gateway方式来快速将gRPC服务以http的方式暴露出来;
    • gRPC-Gateway原理如下图,借助grpc-gateway插件,可以基于proto文件生成反向代理(Reverse Proxy)的代码,这个反向代理运行起来后,对外提供RESTful服务,收到RESTful请求后通过gRPC调用原来的gRPC服务:

    在这里插入图片描述

    • 本文展示了gRPC-Gateway环境搭建、开发、验证的整个过程,由以下步骤组成:
    1. 极速搭建gRPC-Gateway环境;
    2. 编写proto文件;
    3. 根据proto文件生成gRPC、gRPC-Gateway源码;
    4. 添加业务代码;
    5. 编译、运行、验证;

    提前说明文件和目录

    • 本次实战在$GOPATH/src目录下新增文件夹helloworld,里面总共有以下内容:
    [golang@centos7 src]$ tree helloworld/
    helloworld/
    ├── gateway
    │   └── helloworld.gw.go
    ├── helloworld.pb.go
    ├── helloworld.pb.gw.go
    ├── helloworld.proto
    ├── helloworld.swagger.json
    └── server
        └── server.go
    
    • 准备工作完成,接下来正式开始开发;

    前提条件

    • 本文的所有操作都没有用到root账号,而是前文创建的golang账号;
    • 请参照以下两篇文章将GO环境和gRPC环境搭建好:
    1. 在CentOS7部署和设置GO
    2. GO的gRPC开发环境准备

    极速搭建gRPC-Gateway环境

    • 所谓的搭建gRPC-Gateway环境,其实是完成以下三件事:

    在这里插入图片描述

    1. 在搭建环境时参考了一些网上的文章,结果遇到了各种问题一直没有成功(我当然不会认为文章有问题,必须认识到是自己能力不足的原因所致);
    2. 经过反复折腾后终于成功后,我把所有操作做成一个shell脚本,执行以下命令即可完成上图中的所有操作:
    curl -o install-grpc-gateway.sh 
    https://raw.githubusercontent.com/zq2599/blog_demos/master/files/install-grpc-gateway.sh 
    && chmod a+x ./install-grpc-gateway.sh 
    && ./install-grpc-gateway.sh
    
    1. 进入$GOPATH/bin目录,可见新增两个文件protoc-gen-grpc-gatewayprotoc-gen-swagger
    [golang@centos7 ~]$ cd $GOPATH/bin
    [golang@centos7 bin]$ ls -al
    总用量 26708
    drwxrwxr-x. 2 golang golang      98 12月 19 08:59 .
    drwxrwxr-x. 5 golang golang      39 12月 19 08:21 ..
    -rwxr-x---. 1 golang golang 5253272 12月 19 08:20 protoc
    -rwxrwxr-x. 1 golang golang 8461147 12月 19 08:21 protoc-gen-go
    -rwxrwxr-x. 1 golang golang 6717463 12月 19 08:59 protoc-gen-grpc-gateway
    -rwxrwxr-x. 1 golang golang 6908535 12月 19 08:59 protoc-gen-swagger
    
    • 现在环境准备好了,开始开发;

    编写proto文件

    • $GOPATH/src目录下,新建文件夹helloworld,里面新建文件helloworld.proto,内容如下,有几处要注意的地方稍后会说:
    // 协议类型
    syntax = "proto3";
    
    // 包名
    package helloworld;
    
    import "google/api/annotations.proto";
    
    // 定义的服务名
    service Greeter {
      // 具体的远程服务方法
      rpc SayHello (HelloRequest) returns (HelloReply) {
        option (google.api.http) = {
          post: "/helloworld"
          body: "*"
        };
      }
    }
    
    // SayHello方法的入参,只有一个字符串字段
    message HelloRequest {
      string name = 1;
    }
    
    // SayHello方法的返回值,只有一个字符串字段
    message HelloReply {
      string message = 1;
    }
    
    • 上述proto文件有以下几处要注意的地方:
    1. 整个文件其实就是以 《初试GO版gRPC开发》一文中的helloworld.proto为基础,增加了两处内容;
    2. 增加的第一处,是用import关键词导入google/api/annotations.proto
    3. 增加的第二处,是SayHello方法的声明处,增加了option配置,作用是配置SayHello方法对外暴露的RESTful接口的信息;
    4. 在使用protoc-gen-grpc-gateway的时候,上述两处配置会被识别到并生成对应的代码;

    根据proto文件生成gRPC、gRPC-Gateway源码

    1. proto文件编写完成,接下来是生成gRPC、gRPC-Gateway的源码;
    2. 生成gRPC源码的命令咱们前面的文章中已经用过,如下:
    protoc -I. 
    -I$GOPATH/src 
    -I$GOPATH/src/github.com/grpc-ecosystem/grpc-gateway/third_party/googleapis 
    --go_out=plugins=grpc:. 
    helloworld.proto
    
    1. 执行完成后会在当前目录生成helloworld.pb.go文件;
    2. 执行生成gRPC-Gateway源码的命令:
    protoc -I. 
    -I$GOPATH/src 
    -I$GOPATH/src/github.com/grpc-ecosystem/grpc-gateway/third_party/googleapis 
    --grpc-gateway_out=logtostderr=true:. 
    helloworld.proto
    
    1. 执行完成后会在当前目录生成helloworld.pb.gw.go文件;
    2. 执行生成swagger文件的命令:
    protoc -I. 
    -I$GOPATH/src 
    -I$GOPATH/src/github.com/grpc-ecosystem/grpc-gateway/third_party/googleapis 
    --swagger_out=logtostderr=true:. 
    helloworld.proto
    
    1. 执行完成后会在当前目录生成helloworld.swagger.json文件;
    2. 至此,helloworld目录下一共有这些内容:
    [golang@centos7 src]$ tree helloworld/
    helloworld/
    ├── helloworld.pb.go
    ├── helloworld.pb.gw.go
    ├── helloworld.proto
    └── helloworld.swagger.json
    
    0 directories, 4 files
    
    1. 接下来开始编码,把运行整个服务所需的代码补全;
    2. 由于篇幅限制,本文暂不提及swagger相关的开发和验证,因此生成的helloworld.swagger.json文件本篇用不上,留待下一篇文章使用;

    编写服务端代码server.go并启动

    1. 接下来编写服务端代码server.go,这个和《初试GO版gRPC开发》中的server.go内容一样;
    2. $GOPATH/src/helloworld目录下新建文件夹server,在此文件夹下新建server.go,内容如下,已经添加详细注释:
    package main
    
    import (
    	"context"
    	"log"
    	"net"
    
    	"google.golang.org/grpc"
    	pb "helloworld"
    )
    
    const (
    	port = ":50051"
    )
    
    // 定义结构体,在调用注册api的时候作为入参,
    // 该结构体会带上SayHello方法,里面是业务代码
    // 这样远程调用时就执行了业务代码了
    type server struct {
    	// pb.go中自动生成的,是个空结构体
    	pb.UnimplementedGreeterServer
    }
    
    // 业务代码在此写,客户端远程调用SayHello时,
    // 会执行这里的代码
    func (s *server) SayHello(ctx context.Context, in *pb.HelloRequest) (*pb.HelloReply, error) {
    	// 打印请求参数
    	log.Printf("Received: %v", in.GetName())
    	// 实例化结构体HelloReply,作为返回值
    	return &pb.HelloReply{Message: "Hello " + in.GetName()}, nil
    }
    
    func main() {
    	// 要监听的协议和端口
    	lis, err := net.Listen("tcp", port)
    	if err != nil {
    		log.Fatalf("failed to listen: %v", err)
    	}
    
    	// 实例化gRPC server结构体
    	s := grpc.NewServer()
    
    	// 服务注册
    	pb.RegisterGreeterServer(s, &server{})
    
    	log.Println("开始监听,等待远程调用...")
    
    	if err := s.Serve(lis); err != nil {
    		log.Fatalf("failed to serve: %v", err)
    	}
    }
    
    1. 在server.go所在目录执行go run server.go,控制台提示如下:
    [golang@centos7 server]$ go run server.go 
    2020/12/13 08:20:32 开始监听,等待远程调用...
    
    1. 此时gRPC的服务端已启动,可以响应远程调用,接下来开发反向代理(Reverse Proxy);

    编写反向代理(Reverse Proxy)代码helloworld.gw.go并启动

    • 接下来编反向代理(Reverse Proxy)代码helloworld.gw.go
    • $GOPATH/src/helloworld目录下新建文件夹gateway,在此文件夹下新建helloworld.gw.go,内容如下,有几处要注意的地方稍后会说明:
    package main
    
    import (
    	"flag"
    	"fmt"
    	"net/http"
    	gw "helloworld"
    
    	"github.com/grpc-ecosystem/grpc-gateway/runtime"
    	"golang.org/x/net/context"
    	"google.golang.org/grpc"
    )
    
    var (
    	echoEndpoint = flag.String("echo_endpoint", "localhost:50051", "endpoint of YourService")
    )
    
    func run() error {
    
    	ctx := context.Background()
    	ctx, cancel := context.WithCancel(ctx)
    	defer cancel()
    	mux := runtime.NewServeMux()
    	opts := []grpc.DialOption{grpc.WithInsecure()}
    	err := gw.RegisterGreeterHandlerFromEndpoint(ctx, mux, *echoEndpoint, opts)
    
    	if err != nil {
    		return err
    	}
    
    	return http.ListenAndServe(":9090", mux)
    }
    
    func main() {
    	if err := run(); err != nil {
    		fmt.Print(err.Error())
    	}
    }
    
    1. 第一处要注意的地方,是调用http.ListenAndServe监听9090端口,这是对外提供RESTful服务的端口;
    2. 第二处要注意的地方,是echoEndpoint配置了将外部RESTful请求转发到server.go提供gRPC服务的入口处;
    3. 第三处要注意的地方,是调用了自动生成代码中的RegisterGreeterHandlerFromEndpoint方法完成上下游调用的绑定;
    • hellowworld.gw.go所在目录执行go run hellowworld.gw.go,开始监听9090端口的web请求;

    验证

    1. 在本机上验证,用curl发送请求:
    curl 
    -X POST 
    -d '{"name": "will"}' 
    192.168.133.203:9090/helloworld
    
    1. 收到响应如下,这是来自server.go的内容,可见http请求通过Reserve Proxy到达了真实的gRPC服务提供者,并顺利返回给调用方:
    {"message":"Hello will"}
    
    1. 去看server.go的日志如下:
    [golang@centos7 server]$ go run server.go 
    2020/12/19 14:16:47 开始监听,等待远程调用...
    2020/12/19 14:24:35 Received: will
    
    1. 还可以在其他机器上通过postman验证,记得关闭服务所在机器的防火墙,请求和响应如下,注意按数字顺序设置和观察:

    在这里插入图片描述

    • 至此,将gRPC服务快速暴露为RESTful服务的实战就完成了,如果您正在做这方面的尝试,希望本文能给您一些参考,接下来的文章咱们一起把swagger补全,让开发和联调更加高效;

    你不孤单,欣宸原创一路相伴

    1. Java系列
    2. Spring系列
    3. Docker系列
    4. kubernetes系列
    5. 数据库+中间件系列
    6. DevOps系列

    欢迎关注公众号:程序员欣宸

    微信搜索「程序员欣宸」,我是欣宸,期待与您一同畅游Java世界...
    https://github.com/zq2599/blog_demos

  • 相关阅读:
    《React+Redux前端开发实战》笔记2:基于Webpack构建的Hello World案例(上)
    Micro:bit 03:剪刀石头布进阶版
    c++05:二维数组
    c++04:数组的应用:点灯问题
    c++03:质合判断
    Micro:bit第二集——温控与风扇
    c++之二:利用一维数组求最大,最小,平均值
    c++首发:软件安装&helloworld
    scratch第十二集——星图
    scratch第十一集——黄金矿工
  • 原文地址:https://www.cnblogs.com/bolingcavalry/p/15155000.html
Copyright © 2020-2023  润新知