【笔记】GRPCGateway学习笔记

前言

GRPCGateway学习笔记

下载依赖

1
2
3
go install github.com/grpc-ecosystem/grpc-gateway/v2/protoc-gen-grpc-gateway@latest
go install google.golang.org/protobuf/cmd/protoc-gen-go@latest
go install google.golang.org/grpc/cmd/protoc-gen-go-grpc@latest

下载Google提供的Protobuf

1
2
3
4
5
mkdir -p google/api
cd google/api
wget https://raw.githubusercontent.com/googleapis/googleapis/master/google/api/annotations.proto
wget https://raw.githubusercontent.com/googleapis/googleapis/master/google/api/http.proto
cd ../..
1
2
3
4
+ google
+ api
- annotations.proto
- http.proto

创建基本的GRPC结构

client/main.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
package main

import (
"context"
"fmt"
"github.com/feiju12138/grpc/test"
"google.golang.org/grpc"
)

func main() {
listen, _ := grpc.Dial("127.0.0.1:8888", grpc.WithInsecure())
client := test.NewTestServiceClient(listen)
res, _ := client.Test(context.Background(), &test.Req{Message: "1"})
fmt.Println(res.GetMessage())
}
service/main.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
package main

import (
"context"
"github.com/feiju12138/grpc/test"
"google.golang.org/grpc"
"net"
)

type TestService struct {
test.UnimplementedTestServiceServer
}

func (*TestService) Test(context context.Context, req *test.Req) (*test.Res, error) {
return &test.Res{Message: req.GetMessage()}, nil
}

func main() {
listen, _ := net.Listen("tcp", "0.0.0.0:8888")
server := grpc.NewServer()
test.RegisterTestServiceServer(server, &TestService{})
server.Serve(listen)
}
test/test.proto
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
syntax = "proto3";

option go_package="github.com/feiju12138/grpc/test;test";

package test;

message Req {
string message = 1;
}

message Res {
string message = 1;
}

service TestService {
rpc Test(Req) returns (Res);
}

在Protobuf的service中添加option

test/test.proto
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
syntax = "proto3";

option go_package="github.com/feiju12138/grpc/test;test";

import "google/api/annotations.proto";

package test;

message Req {
string message = 1;
}

message Res {
string message = 1;
}

service TestService {
rpc Test(Req) returns (Res) {
option(google.api.http) = {
post:"/api/test",
body:"*",
};
};
}

GRPC生成Go代码

-I ./proto:指定项目根目录的所在路径
--go_out ./--go-grpc_out ./--grpc-gateway_out .:指定相对于项目根目录的路径
./test/test.proto:Protobuf的所在路径

1
2
3
4
5
protoc -I ./ \
--go_out ./ --go_opt paths=source_relative \
--go-grpc_out ./ --go-grpc_opt paths=source_relative \
--grpc-gateway_out ./ --grpc-gateway_opt paths=source_relative \
./test/test.proto
  • 会在Protobuf文件同级目录下生成test.pb.gotest.pb.gw.gotest_grpc.pb.go文件

在服务端添加对外暴露的代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
package main

import (
"context"
"github.com/feiju12138/grpc/test"
"github.com/grpc-ecosystem/grpc-gateway/v2/runtime"
"google.golang.org/grpc"
"net"
"net/http"
"sync"
)

type TestService struct {
test.UnimplementedTestServiceServer
}

func (*TestService) Test(context context.Context, req *test.Req) (*test.Res, error) {
return &test.Res{Message: req.GetMessage() + "0"}, nil
}

func registerGateway(waitGroup *sync.WaitGroup) {
// 创建中间层
conn, _ := grpc.DialContext(context.Background(), "127.0.0.1:8888", grpc.WithBlock(), grpc.WithInsecure())
mux := runtime.NewServeMux()
// 创建http服务
gatewayServer := &http.Server{
Handler: mux,
Addr: "0.0.0.0:8889",
}
// 启动网关服务
gatewayServer.ListenAndServe()
// 注册网关
test.RegisterTestServiceHandler(context.Background(), mux, conn)
waitGroup.Done()
}

func registerGRPC(waitGroup *sync.WaitGroup) {
listen, _ := net.Listen("tcp", "0.0.0.0:8888")
server := grpc.NewServer()
test.RegisterTestServiceServer(server, &TestService{})
server.Serve(listen)
waitGroup.Done()
}

func main() {
waitGroup := sync.WaitGroup{}
waitGroup.Add(2)
go registerGateway(&waitGroup)
go registerGRPC(&waitGroup)
waitGroup.Wait()
}

GRPCGateway配置

处理GET请求

request
1
2
GET http://localhost:8080/api/test?message=1
Accept: application/json

请求参数映射为字符串

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
syntax = "proto3";

option go_package="github.com/feiju12138/grpc/test;test";

import "google/api/annotations.proto";

package test;

message Req {
string message = 1;
}

message Res {
string message = 1;
}

service TestService {
rpc Test(Req) returns (Res) {
option(google.api.http) = {
get:"/api/test",
};
};
}

请求参数映射为结构体

request
1
2
GET http://localhost:8080/api/test?message.key=1
Accept: application/json
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
syntax = "proto3";

option go_package="github.com/feiju12138/grpc/test;test";

import "google/api/annotations.proto";

package test;

message Message {
string key = 1
}

message Req {
Message message = 1;
}

message Res {
string message = 1;
}

service TestService {
rpc Test(Req) returns (Res) {
option(google.api.http) = {
get:"/api/test",
};
};
}

处理POST请求

请求参数映射为字符串

从query获取数据
request
1
2
POST http://localhost:8080/api/test?message=1
Accept: application/json
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
syntax = "proto3";

option go_package="github.com/feiju12138/grpc/test;test";

import "google/api/annotations.proto";

package test;

message Req {
string message = 1;
}

message Res {
string message = 1;
}

service TestService {
rpc Test(Req) returns (Res) {
option(google.api.http) = {
post:"/api/test",
body:"*",
};
};
}
从body获取数据
request
1
2
3
4
POST http://localhost:8080/api/test
Accept: application/json

"1"
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
syntax = "proto3";

option go_package="github.com/feiju12138/grpc/test;test";

import "google/api/annotations.proto";

package test;

message Req {
string message = 1;
}

message Res {
string message = 1;
}

service TestService {
rpc Test(Req) returns (Res) {
option(google.api.http) = {
post:"/api/test",
body:"*",
};
};
}
从path获取数据
request
1
2
POST http://localhost:8080/api/test/1
Accept: application/json
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
syntax = "proto3";

option go_package="github.com/feiju12138/grpc/test;test";

import "google/api/annotations.proto";

package test;

message Req {
string message = 1;
}

message Res {
string message = 1;
}

service TestService {
rpc Test(Req) returns (Res) {
option(google.api.http) = {
post:"/api/test/{message}",
body:"*",
};
};
}

请求参数映射为结构体

从query获取数据
request
1
2
POST http://localhost:8080/api/test?message.key=1
Accept: application/json
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
syntax = "proto3";

option go_package="github.com/feiju12138/grpc/test;test";

import "google/api/annotations.proto";

package test;

message Message {
string key = 1
}

message Req {
Message message = 1;
}

message Res {
string message = 1;
}

service TestService {
rpc Test(Req) returns (Res) {
option(google.api.http) = {
post:"/api/test",
body:"message",
};
};
}
从body获取数据
request
1
2
3
4
POST http://localhost:8080/api/test
Accept: application/json

{"key": "value"}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
syntax = "proto3";

option go_package="github.com/feiju12138/grpc/test;test";

import "google/api/annotations.proto";

package test;

message Message {
string key = 1
}

message Req {
Message message = 1;
}

message Res {
string message = 1;
}

service TestService {
rpc Test(Req) returns (Res) {
option(google.api.http) = {
post:"/api/test",
body:"message",
};
};
}

完成

参考文献

Github——go圈里最会写js的奇淼