gRPC学习之五:gRPC-Gateway实战

[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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值