gRPC-四种模式实践
2022-03-09
· 1821 words · ~ 9 min read
本文介绍如何使用 gRPC 的四种模式
gRPC 共有四种模式:简单模式、服务端流模式、客户端流模式、双向流模式。
在开始之前,我们首先新建proto/hello.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
25
26
27
28
29
30
31
// 表示当前使用的语法版本
syntax = "proto3" ;
//.代表当前文件夹,分号后面是生成go文件引入的包名,abc具体的值根据项目需求而定。
// 生成.go 文件的package
option go_package = ".;abc" ;
// 定义一个Request
// 类型 变量名 标志(标志在相同目录中必须唯一)
message LoginRequest {
string username = 1 ;
string password = 2 ;
}
message LoginResponse {
int32 code = 1 ;
string meg = 2 ;
}
// 定义一个服务
service HelloService {
// 一元到一元 的服务
rpc HelloUnaryToUnary ( LoginRequest ) returns ( LoginResponse ){};
// 一元到流的服务 服务端流
rpc HelloUnary2Stream ( LoginRequest ) returns ( stream LoginResponse ){};
// 流到一元的服务 客户端流
rpc HelloStream2Unary ( stream LoginRequest ) returns ( LoginResponse ){};
// 双向流的服务
rpc HelloStream2Stream ( stream LoginRequest ) returns ( stream LoginResponse ){};
}
在此之前我们还要下载 go 的依赖
在项目中
1
2
3
4
5
go mod init test
go get -u google . golang . org / grpc
go get -u github . com / golang / protobuf
go get -u github . com / golang / protobuf / protoc-gen -go
go get github . com / google / uuid
此外还要安装protoc安装完成之后,在项目根目录执行
1
protoc - -proto_path = proto proto /*. proto - -go_out = plugins = grpc : ./ proto
在 proto 文件下就会有hello.pb.go生成。
简单模式
类似于普通的 http 请求,客户端请求 request 服务端进行响应 response。
我说一句话你说一句话。
我们首先实现客户端。client/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
24
25
26
27
28
29
30
31
32
33
34
35
36
package main
import (
"context"
"fmt"
"github.com/google/uuid"
"google.golang.org/grpc"
"io"
"log"
abc "test/proto"
)
func main () {
// 1. 创建一个连接
conn , err := grpc . Dial ( "127.0.0.1:8888" , grpc . WithInsecure ())
if err != nil {
log . Fatal ( "cannot dial server :" , err )
}
// 记着 close
defer conn . Close ()
// 2. 创建一个 client proto 生成的 go 文件中有一个创建 client 的方法
client := abc . NewHelloServiceClient ( conn )
// 客户端
{
req := & abc . LoginRequest { Username : "admin" , Password : "123456" }
// 3. 调用服务,传一个 request
response , err := client . HelloUnaryToUnary ( context . Background (), req )
if err != nil {
log . Fatalf ( "cannot receive response :%v" , err )
}
log . Printf ( "response :%v\n" , response )
}
实现服务端server/server/hello_service.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
52
package server
import (
"github.com/google/uuid"
"golang.org/x/net/context"
"google.golang.org/grpc/codes"
"google.golang.org/grpc/status"
"io"
"log"
abc "test/proto"
)
// 定义 server 的结构体
type HelloServer struct {
}
func NewHelloServer () * HelloServer {
return & HelloServer {}
}
// 实现一元 - 一元服务
func ( server * HelloServer ) HelloUnaryToUnary ( ctx context . Context , req * abc . LoginRequest ) ( * abc . LoginResponse , error ) {
// 这是一个简单是示例,所以就直接写死了
// 拿到 request,如果符合要求就响应 成功,不符合要求就响应 没有该用户。
if req . GetUsername () == "admin" && req . GetPassword () == "123456" {
log . Printf ( "request :%v" , req )
resp := & abc . LoginResponse {
Code : 200 ,
Meg : "成功" ,
}
return resp , nil
} else {
resp := & abc . LoginResponse {
Code : 404 ,
Meg : "没有该用户" ,
}
return resp , nil
}
}
// 空实现
func ( server * HelloServer ) HelloUnary2Stream ( req * abc . LoginRequest , stream abc . HelloService_HelloUnary2StreamServer ) error {
return nil
}
// 空实现
func ( server * HelloServer ) HelloStream2Unary ( stream abc . HelloService_HelloStream2UnaryServer ) error {
return nil
}
// 空实现
func ( server * HelloServer ) HelloStream2Stream ( stream abc . HelloService_HelloStream2StreamServer ) error {
return nil
}
实现服务端server/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
24
25
26
27
28
29
30
31
package main
import (
"google.golang.org/grpc"
"log"
"net"
abc "test/proto"
"test/server/server"
)
func main () {
// 1. 拿出服务
grpcSever := grpc . NewServer ()
// 2. 挂载方法 就是上面实现的方法
helloService := server . NewHelloServer ()
// 3. 注册服务
abc . RegisterHelloServiceServer ( grpcSever , helloService )
log . Printf ( "gRPC is running ......" )
// 4. 创建监听
listen , err := net . Listen ( "tcp" , ":8888" )
if err != nil {
log . Fatalf ( "cannot listen port 8888 :%v" , err )
}
err = grpcSever . Serve ( listen )
if err != nil {
log . Fatalf ( "gRPC server err: %s\n" , err )
}
}
我们分别启动服务端和客户端。
在server/目录
1
2
3
go run .\ main . go
2022 / 03 / 09 10 : 15 : 08 gRPC is running ......
2022 / 03 / 09 10 : 15 : 22 request : username : "admin" password : "123456"
在client/目录
1
2
go run .\ main . go
2022 / 03 / 09 10 : 15 : 22 response : code : 200 meg : "成功"
现在我们就实现了一个简单的一元服务。
服务端流模式
客户端发送一个 request,服务端的是一个响应流。
我说一句话,你说一大堆。
client.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
{
// 客户端向服务端发一条消息,
stream , err := client . HelloUnary2Stream ( context . Background (), req )
if err != nil {
log . Fatalf ( "cannot receiver stream :%v" , err )
}
// 客户端不断收服务端的消息流
for {
// 接受服务端的流
resp , err := stream . Recv ()
// 没有错误就是收到了
if err == nil {
log . Printf ( "receiver :%v" , resp )
}
// 接受完了就要结束了
if err == io . EOF {
log . Printf ( "receiver end..." )
break
}
if err != nil {
log . Fatalf ( "unknow error:%v" , err )
}
}
// 接受完了之后关闭通道
err = stream . CloseSend ()
if err != nil {
log . Fatal ( "cannot close stream" )
}
}
实现func (server *HelloServer) HelloUnary2Stream(req *abc.LoginRequest, stream abc.HelloService_HelloUnary2StreamServer) error方法
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
func ( server * HelloServer ) HelloUnary2Stream ( req * abc . LoginRequest , stream abc . HelloService_HelloUnary2StreamServer ) error {
// 服务端收到一条消息
log . Printf ( "request :%v" , req )
// 不断向客服端发消息
for i := 0 ; i < 10 ; i ++ {
username , _ := uuid . NewRandom ()
response := & abc . LoginResponse { Code : int32 ( i ), Meg : username . String ()}
err := stream . Send ( response )
log . Printf ( "send %v %v" , response . Code , response . Meg )
if err != nil {
return err
}
}
return nil
}
服务端
1
2
3
4
5
6
7
8
9
10
11
12
13
PS D : \ code \ go \ test \ server > go run . \ main . go
2022 / 03 / 09 10 : 34 : 28 gRPC is running ......
2022 / 03 / 09 10 : 34 : 35 request : username : "admin" password : "123456"
2022 / 03 / 09 10 : 34 : 35 send 0 6497 cd6a - 11 ce - 4 d76 - b9a6 - 7e2 da224199b
2022 / 03 / 09 10 : 34 : 35 send 1 1119826 f - c7c1 - 41 cb - 8 d17 - 19 c827d53281
2022 / 03 / 09 10 : 34 : 35 send 2 7 c90922f - 212 d - 4524 - b225 - d6c2c2e0977a
2022 / 03 / 09 10 : 34 : 35 send 3 11 cafa80 - ce70 - 4e22 - 98 a4 - 6 af1e6c2b545
2022 / 03 / 09 10 : 34 : 35 send 4 ed87b66c - 6 d18 - 4 de8 - 9285 - d8587a8f6a53
2022 / 03 / 09 10 : 34 : 35 send 5 a0db893c - 9 dfa - 4 dac - 9 b77 - a39e88763f0d
2022 / 03 / 09 10 : 34 : 35 send 6 9914e70 f - a732 - 4002 - b000 - 7 ded2c66918e
2022 / 03 / 09 10 : 34 : 35 send 7 b0933c28 - 07 8 c - 48 c6 - 903 d - b3b936fa325f
2022 / 03 / 09 10 : 34 : 35 send 8 e24a9de1 - f662 - 47 c9 - b7ea - bd9126687b97
2022 / 03 / 09 10 : 34 : 35 send 9 18e6 e09a - 206 c - 4240 - 9 a27 - 2 f27cf5fa0e0
客户端
1
2
3
4
5
6
7
8
9
10
11
2022 / 03 / 09 10 : 34 : 35 receiver : meg : "6497cd6a-11ce-4d76-b9a6-7e2da224199b"
2022 / 03 / 09 10 : 34 : 35 receiver : code : 1 meg : "1119826f-c7c1-41cb-8d17-19c827d53281"
2022 / 03 / 09 10 : 34 : 35 receiver : code : 2 meg : "7c90922f-212d-4524-b225-d6c2c2e0977a"
2022 / 03 / 09 10 : 34 : 35 receiver : code : 3 meg : "11cafa80-ce70-4e22-98a4-6af1e6c2b545"
2022 / 03 / 09 10 : 34 : 35 receiver : code : 4 meg : "ed87b66c-6d18-4de8-9285-d8587a8f6a53"
2022 / 03 / 09 10 : 34 : 35 receiver : code : 5 meg : "a0db893c-9dfa-4dac-9b77-a39e88763f0d"
2022 / 03 / 09 10 : 34 : 35 receiver : code : 6 meg : "9914e70f-a732-4002-b000-7ded2c66918e"
2022 / 03 / 09 10 : 34 : 35 receiver : code : 7 meg : "b0933c28-078c-48c6-903d-b3b936fa325f"
2022 / 03 / 09 10 : 34 : 35 receiver : code : 8 meg : "e24a9de1-f662-47c9-b7ea-bd9126687b97"
2022 / 03 / 09 10 : 34 : 35 receiver : code : 9 meg : "18e6e09a-206c-4240-9a27-2f27cf5fa0e0"
2022 / 03 / 09 10 : 34 : 35 receiver end ...
客户端流模式
客户端发送流,服务端只是一个响应。
我说了一大堆,你回了一句话。
client.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
{
stream , err := client . HelloStream2Unary ( context . Background ())
if err != nil {
log . Fatal ( "cannot send " )
}
// 发送 10 条请求流
for i := 0 ; i < 10 ; i ++ {
req := & abc . LoginRequest { Username : uuid . NewString (), Password : uuid . NewString ()}
err := stream . Send ( req )
if err != nil {
log . Fatalf ( "cannot send %v ,err:%v" , req , err )
}
}
log . Printf ( "send end..." )
// 关闭 发送通道
err = stream . CloseSend ()
if err != nil {
log . Fatal ( "cannot close stream" )
}
// 接受响应
res , err := stream . CloseAndRecv ()
if err != nil {
log . Fatal ( "cannot receive response" )
}
log . Printf ( "receive response %v" , res )
}
server.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
func ( server * HelloServer ) HelloStream2Unary ( stream abc . HelloService_HelloStream2UnaryServer ) error {
for {
req , err := stream . Recv ()
if err == io . EOF {
log . Print ( "no more data" )
break
}
if err != nil {
return logErr ( status . Errorf ( codes . Unknown , "cannot receive request" ))
}
log . Printf ( "receiver :%v" , req )
}
err := stream . SendAndClose ( & abc . LoginResponse { Code : 200 , Meg : "接受完毕" })
if err != nil {
return logErr ( status . Errorf ( codes . Unknown , "cannot send response" ))
}
return nil
}
服务端
1
2
3
4
5
6
7
8
9
10
11
2022 / 03 / 09 10 : 53 : 26 receiver : username : "6a57a4d0-aaa3-41de-bd16-2da29d3a0ff5" password : "1aade1e4-135d-4734-a29c-6a3fd23a5597"
2022 / 03 / 09 10 : 53 : 26 receiver : username : "7e04862e-efae-439e-94e5-ee0e394002d6" password : "2837e260-c90a-433c-9822-a378ff99fbe9"
2022 / 03 / 09 10 : 53 : 26 receiver : username : "4204b5b5-3df0-4a61-91f1-6940b14e809f" password : "c139d1f7-89c0-4628-961b-db3c0b2fa23a"
2022 / 03 / 09 10 : 53 : 26 receiver : username : "52c5153d-f35d-4bc6-ad8c-127df19250fe" password : "1985a5cc-b200-431c-959e-9220a1c8fa85"
2022 / 03 / 09 10 : 53 : 26 receiver : username : "6f0fc379-93c9-46f5-a374-9d9851a9f56a" password : "2166039e-1b97-4887-a0d1-d6a61bafef87"
2022 / 03 / 09 10 : 53 : 26 receiver : username : "da7e2195-ec64-448c-b8e6-1e58580b1637" password : "279d7b32-ffcd-4be2-8111-e0cb557e6bd0"
2022 / 03 / 09 10 : 53 : 26 receiver : username : "7dc698a9-e77a-491d-99f3-d36f17f8ffc0" password : "1b449f77-c6e1-413d-a88f-6b7a8f7b1bb7"
2022 / 03 / 09 10 : 53 : 26 receiver : username : "186de3d9-de9c-4243-aef7-fc9800991349" password : "731f6ef2-8241-400e-bc57-509cb8cc75e8"
2022 / 03 / 09 10 : 53 : 26 receiver : username : "5fa98e03-4a95-4653-bc1a-4f0356bcca07" password : "f3cc126c-b4c8-474a-b93e-6d4064545f84"
2022 / 03 / 09 10 : 53 : 26 receiver : username : "b2157cc2-8244-4e10-887f-b82e29617ce2" password : "f0a5c65e-dcf9-454e-88dd-0b985c2a7cdf"
2022 / 03 / 09 10 : 53 : 26 no more data
客户端
1
2
3
4
5
6
7
8
9
10
11
12
13
go run .\ main . go
2022 / 03 / 09 10 : 53 : 26 send req : username : "6a57a4d0-aaa3-41de-bd16-2da29d3a0ff5" password : "1aade1e4-135d-4734-a29c-6a3fd23a5597"
2022 / 03 / 09 10 : 53 : 26 send req : username : "7e04862e-efae-439e-94e5-ee0e394002d6" password : "2837e260-c90a-433c-9822-a378ff99fbe9"
2022 / 03 / 09 10 : 53 : 26 send req : username : "4204b5b5-3df0-4a61-91f1-6940b14e809f" password : "c139d1f7-89c0-4628-961b-db3c0b2fa23a"
2022 / 03 / 09 10 : 53 : 26 send req : username : "52c5153d-f35d-4bc6-ad8c-127df19250fe" password : "1985a5cc-b200-431c-959e-9220a1c8fa85"
2022 / 03 / 09 10 : 53 : 26 send req : username : "6f0fc379-93c9-46f5-a374-9d9851a9f56a" password : "2166039e-1b97-4887-a0d1-d6a61bafef87"
2022 / 03 / 09 10 : 53 : 26 send req : username : "da7e2195-ec64-448c-b8e6-1e58580b1637" password : "279d7b32-ffcd-4be2-8111-e0cb557e6bd0"
2022 / 03 / 09 10 : 53 : 26 send req : username : "7dc698a9-e77a-491d-99f3-d36f17f8ffc0" password : "1b449f77-c6e1-413d-a88f-6b7a8f7b1bb7"
2022 / 03 / 09 10 : 53 : 26 send req : username : "186de3d9-de9c-4243-aef7-fc9800991349" password : "731f6ef2-8241-400e-bc57-509cb8cc75e8"
2022 / 03 / 09 10 : 53 : 26 send req : username : "5fa98e03-4a95-4653-bc1a-4f0356bcca07" password : "f3cc126c-b4c8-474a-b93e-6d4064545f84"
2022 / 03 / 09 10 : 53 : 26 send req : username : "b2157cc2-8244-4e10-887f-b82e29617ce2" password : "f0a5c65e-dcf9-454e-88dd-0b985c2a7cdf"
2022 / 03 / 09 10 : 53 : 26 send end ...
2022 / 03 / 09 10 : 53 : 26 receive response code : 200 meg : "接受完毕"
双向流模式。
两个都不断在向对方发送流。
两个人都在不断说话。可能是你说一句我回 0-N 句,我说一句你回 0-N。
client.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
{
stream , err := client . HelloStream2Stream ( context . Background ())
if err != nil {
log . Fatalf ( "unknow error %v" , err )
}
// 由于双方都需要不断发收,所以不能阻塞在一处,通过 chan 进行 error 的通信
waitResponse := make ( chan error )
// 开启一个携程,专门收
go func () {
for {
res , err := stream . Recv ()
if err == io . EOF {
log . Printf ( "no more response" )
waitResponse <- nil
return
}
if err != nil {
waitResponse <- fmt . Errorf ( "cannot receive stream response %v" , err )
return
}
log . Printf ( "received response :%v" , res )
}
}()
// 继续发
for i := 0 ; i < 10 ; i ++ {
req := & abc . LoginRequest { Username : uuid . NewString (), Password : uuid . NewString ()}
err := stream . Send ( req )
log . Printf ( "send %v" , req )
if err != nil {
log . Fatal ( "unknow" )
}
}
// 关闭发送
err = stream . CloseSend ()
if err != nil {
log . Fatal ( err )
}
// 如果没有遇到 error 会一直阻塞到这,直到遇到 error
err = <- waitResponse
log . Printf ( "end %v" , err )
}
server.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
func ( server * HelloServer ) HelloStream2Stream ( stream abc . HelloService_HelloStream2StreamServer ) error {
for {
// 不断接受
req , err := stream . Recv ()
if err == io . EOF {
log . Printf ( "no more data" )
break
}
if err != nil {
return logErr ( status . Errorf ( codes . Unknown , "cannot receive stream request :%v" , err ))
}
log . Printf ( "receive data: %v %v" , req . Username , req . Password )
// 将接受到的发送
res := & abc . LoginResponse { Code : 200 , Meg : "receive data username " + req . Username }
err = stream . Send ( res )
if err != nil {
return logErr ( status . Errorf ( codes . Unknown , "cannot send response %v" , err ))
}
}
return nil
}
// 打印并返回
func logErr ( err error ) error {
if err != nil {
log . Print ( err )
}
return err
}
服务端
1
2
3
4
5
6
7
8
9
10
11
2022/03/09 10:53:26 receiver :username:"6a57a4d0-aaa3-41de-bd16-2da29d3a0ff5" password:"1aade1e4-135d-4734-a29c-6a3fd23a5597"
2022/03/09 10:53:26 receiver :username:"7e04862e-efae-439e-94e5-ee0e394002d6" password:"2837e260-c90a-433c-9822-a378ff99fbe9"
2022/03/09 10:53:26 receiver :username:"4204b5b5-3df0-4a61-91f1-6940b14e809f" password:"c139d1f7-89c0-4628-961b-db3c0b2fa23a"
2022/03/09 10:53:26 receiver :username:"52c5153d-f35d-4bc6-ad8c-127df19250fe" password:"1985a5cc-b200-431c-959e-9220a1c8fa85"
2022/03/09 10:53:26 receiver :username:"6f0fc379-93c9-46f5-a374-9d9851a9f56a" password:"2166039e-1b97-4887-a0d1-d6a61bafef87"
2022/03/09 10:53:26 receiver :username:"da7e2195-ec64-448c-b8e6-1e58580b1637" password:"279d7b32-ffcd-4be2-8111-e0cb557e6bd0"
2022/03/09 10:53:26 receiver :username:"7dc698a9-e77a-491d-99f3-d36f17f8ffc0" password:"1b449f77-c6e1-413d-a88f-6b7a8f7b1bb7"
2022/03/09 10:53:26 receiver :username:"186de3d9-de9c-4243-aef7-fc9800991349" password:"731f6ef2-8241-400e-bc57-509cb8cc75e8"
2022/03/09 10:53:26 receiver :username:"5fa98e03-4a95-4653-bc1a-4f0356bcca07" password:"f3cc126c-b4c8-474a-b93e-6d4064545f84"
2022/03/09 10:53:26 receiver :username:"b2157cc2-8244-4e10-887f-b82e29617ce2" password:"f0a5c65e-dcf9-454e-88dd-0b985c2a7cdf"
2022/03/09 10:53:26 no more data
客户端
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
go run .\ main . go
2022 / 03 / 09 10 : 53 : 26 send req : username : "6a57a4d0-aaa3-41de-bd16-2da29d3a0ff5" password : "1aade1e4-135d-4734-a29c-6a3fd23a5597"
2022 / 03 / 09 10 : 53 : 26 send req : username : "7e04862e-efae-439e-94e5-ee0e394002d6" password : "2837e260-c90a-433c-9822-a378ff99fbe9"
2022 / 03 / 09 10 : 53 : 26 send req : username : "4204b5b5-3df0-4a61-91f1-6940b14e809f" password : "c139d1f7-89c0-4628-961b-db3c0b2fa23a"
2022 / 03 / 09 10 : 53 : 26 send req : username : "52c5153d-f35d-4bc6-ad8c-127df19250fe" password : "1985a5cc-b200-431c-959e-9220a1c8fa85"
2022 / 03 / 09 10 : 53 : 26 send req : username : "6f0fc379-93c9-46f5-a374-9d9851a9f56a" password : "2166039e-1b97-4887-a0d1-d6a61bafef87"
2022 / 03 / 09 10 : 53 : 26 send req : username : "da7e2195-ec64-448c-b8e6-1e58580b1637" password : "279d7b32-ffcd-4be2-8111-e0cb557e6bd0"
2022 / 03 / 09 10 : 53 : 26 send req : username : "7dc698a9-e77a-491d-99f3-d36f17f8ffc0" password : "1b449f77-c6e1-413d-a88f-6b7a8f7b1bb7"
2022 / 03 / 09 10 : 53 : 26 send req : username : "186de3d9-de9c-4243-aef7-fc9800991349" password : "731f6ef2-8241-400e-bc57-509cb8cc75e8"
2022 / 03 / 09 10 : 56 : 49 received response : code : 200 meg : "receive data username 4b6bcd51-652a-4a8c-af34-85a667ad4957"
2022 / 03 / 09 10 : 56 : 49 send username : "d9a3e249-c85e-4a4f-84a5-e43a787dced0" password : "e5e34dbb-585e-4b5e-83f4-e38f367f8bc0"
2022 / 03 / 09 10 : 56 : 49 send username : "1905bdd1-0a77-4d34-ae38-102038d8a4a9" password : "93bd9964-9c15-40a8-8005-f84d8aada832"
2022 / 03 / 09 10 : 56 : 49 send username : "a1d2b612-03b5-4166-aa1a-ea29e27c8f9e" password : "5b7d1fec-fba3-4120-b24b-8ee6c8f34713"
2022 / 03 / 09 10 : 56 : 49 received response : code : 200 meg : "receive data username 12903ede-ead0-48d9-8240-6f51c9816ac1"
2022 / 03 / 09 10 : 56 : 49 received response : code : 200 meg : "receive data username 91e8bf53-38c7-493d-b9ab-b3ce273a4780"
2022 / 03 / 09 10 : 56 : 49 received response : code : 200 meg : "receive data username c47db986-b1a1-443b-8e39-e815ea4c65a8"
2022 / 03 / 09 10 : 56 : 49 received response : code : 200 meg : "receive data username f8fa740e-c286-4cc4-829b-d36e571084ab"
2022 / 03 / 09 10 : 56 : 49 received response : code : 200 meg : "receive data username de6112ca-8abf-4c08-9f52-f14f448f5772"
2022 / 03 / 09 10 : 56 : 49 received response : code : 200 meg : "receive data username d9a3e249-c85e-4a4f-84a5-e43a787dced0"
2022 / 03 / 09 10 : 56 : 49 received response : code : 200 meg : "receive data username 1905bdd1-0a77-4d34-ae38-102038d8a4a9"
2022 / 03 / 09 10 : 56 : 49 received response : code : 200 meg : "receive data username a1d2b612-03b5-4166-aa1a-ea29e27c8f9e"
2022 / 03 / 09 10 : 56 : 49 no more response
2022 / 03 / 09 10 : 56 : 49 < nil >
#教程
#GRPC
← Previous
为什么 Request.Body 需要被关闭
Next →
为什么 paseto 比 jwt 好?
Table of Contents