上一篇无脑吹了一波 Protobuf,这篇就是实践了,我们项目里基本上都是用 Grpc + Grpc Gateway,即作为内部 API 的通讯,也对外提供 Restful Api。

GRPC

GRPC概述

Google对Grpc的定义:

GRPC 一开始由 google 开发,是一款语言中立、平台中立、开源的远程过程调用(RPC)系统。

在 GRPC 里客户端应用可以像调用本地对象一样直接调用另一台不同的机器上服务端应用的方法,使得您能够更容易地创建分布式应用和服务。与许多 RPC 系统类似,GRPC 也是基于以下理念:定义一个服务,指定其能够被远程调用的方法(包含参数和返回类型)。在服务端实现这个接口,并运行一个 GRPC 服务器来处理客户端调用。在客户端拥有一个存根能够像服务端一样的方法。

GRPC特性

  • 强大的IDL,使用Protocol Buffers作为数据交换的格式,支持v2、v3(推荐v3)
  • 跨语言、跨平台,也就是Grpc支持多种平台和语言
  • 支持HTTP2,双向传输、多路复用、认证等

Grpc-Gateway

Grpc-Gateway概述


Grpc-Gateway 是 ProtoC 的插件。ProtoC 是 Protobuf 底层解析器,它读取 GRPC 服务定义,并生成一个反向代理服务器,将一个 REST 的 JSON API 转换成 GRPC。这个服务器是根据你的 GRPC 定义中的自定义选项生成的。Grpc-Gateway 结构图如下:
grpc-gateway

安装

protoc安装

在这里我以 Windows 为例,首先安装 protoc,下载地址:https://github.com/protocolbuffers/protobuf/releases,在这里我选择的是 protoc-3.9.1-win64.zip,我把它解压到 D:Plug 目录下,然后将 protoc-3.9.1-win64/bin 里面的 protoc.exe 加入到环境变量。加好后,可以查看对应版本,就代表安装好了。
protoc version

grpc-gateway安装

grpc-gateway 的 GitHub 地址:https://github.com/grpc-ecosystem/grpc-gateway

grpc-gateway 使用完全的 Go 语言进行开发,所以安装起来也非常简单,首先需要获取相关的依赖包:

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

下载好之后,就会在你的 GOPATH/bin 目录下出现对应的三个 exe 文件
grpc-gateway

使用

编写proto文件

cd $GOPATH/src/
mkdir -p demo/protobuf
cd demo/protobuf
vim test.proto

syntax = "proto3";

package protobuf;

import "google/api/annotations.proto";

message TestRequest {
    string value = 1;
    string message = 2;
}

message TestResponse {
    string msg = 1;
}

service Test {
    rpc Echo(TestRequest) returns (TestResponse) {
        option (google.api.http) = {
            post: "/v1/test/echo"
            body: "*"
        };
    }
}

然后进入 test.proto 文件同级目录下,运行 protoc 命令,生成 grpc 结构文件和 gateway 文件

protoc -ID:\Plug\protoc-3.9.1-win64\include -I. -I%GOPATH%/src -I%GOPATH%/src/github.com/grpc-    
ecosystem/grpc-gateway/third_party/googleapis --grpc-gateway_out=logtostderr=true:. ./test.proto
protoc -ID:\Plug\protoc-3.9.1-win64\include -I. -I%GOPATH%/src -I%GOPATH%/src/github.com/grpc- 
ecosystem/grpc-gateway/third_party/googleapis --go_out=plugins=grpc:. ./test.proto

在这里 D:/Plug/protoc-3.9.1-win64/include 我用的是 protoc 的绝对路径

最终可以看到以下文件
protobuf

编写Grpc+Grpc-Gateway服务

本来 Grpc 和 Gateway 两个服务应该分开写的,为了省事,我就写在一起了,代码如下:

package main

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

    pb "demo/protobuf"
    gw "demo/protobuf"

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

type test struct {}

func (t *test) Echo(ctx context.Context, in *pb.TestRequest) (*pb.TestResponse, error) {
    log.Println("request: ", in)
    return &pb.TestResponse{Msg: in.Value + in.Message}, nil
}

func runGrpc() error {
    lis, err := net.Listen("tcp", ":35254")

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

    server := grpc.NewServer()
    pb.RegisterTestServer(server, &test{})
    log.Println("rpc服务已经开启")
    go runGrpcGateway()
    return server.Serve(lis)
}

func runGrpcGateway() error {
    ctx := context.Background()
    ctx, cancel := context.WithCancel(ctx)
    defer cancel()

    mux := runtime.NewServeMux(runtime.WithMarshalerOption(runtime.MIMEWildcard,     
&runtime.JSONPb{OrigName: true, EmitDefaults: true}))
    opts := []grpc.DialOption{grpc.WithInsecure()}
    err := gw.RegisterTestHandlerFromEndpoint(ctx, mux, ":35254", opts)
    if err != nil {
        return err
    }
    log.Println("gateway服务已经开启")
    return http.ListenAndServe(":35255", mux)
}

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

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

运行这个网关程序

D:\GOProject\src\demo>go build main.go
D:\GOProject\src\demo>main
2020/03/08 19:00:57 rpc服务已经开启
2020/03/08 19:00:57 gateway服务已经开启

使用 http 的方式调用网关:

curl -X POST -k http://localhost:35255/v1/test/echo -d '{"value" : "Hello", "message" : " World" }'
返回结果:
{
    "msg": "Hello World"
}

或者使用 Postman 模拟请求:
gateway

使用gateway生成swagger文档

protoc -ID:\Plug\protoc-3.9.1-win64\include -I. -I%GOPATH%/src -I%GOPATH%/src/github.com/grpc- 
ecosystem/grpc-gateway/third_party/googleapis --swagger_out=logtostderr=true:. ./test.proto

你会发现 test.proto 同级目录下多了一个 test.swagger.json 文件。打开后效果如下:
swagger

最后修改:2020 年 06 月 09 日 12 : 50 PM
如果觉得我的文章对你有用,请随意赞赏