golang使用protobuf笔记
# 引子
由于项目负载的带宽越来越高,所以迫不得已的要减轻带宽的压力,眼睛只能瞄到了protobuf
这个轻便高效的结构化数据存储格式。
# 基础环境
安装 protobuf
,目前只有 macOS
环境
brew install protobuf
1
以下两个命令我均在项目中执行的,所以
go.mod
里面也顺便也引入了
安装 protoc-gen-go
go install google.golang.org/protobuf/cmd/protoc-gen-go@latest
1
安装 protoc-gen-go-grpc
go install google.golang.org/grpc/cmd/protoc-gen-go-grpc@latest
1
# 创建protobuf
文件
syntax = "proto3";
import "google/protobuf/struct.proto";
// 实际测试下面这行注释代码没什么卵用
// package protoInfo;
option go_package = "./protoInfo";
// 返回数据
message AuthInfoResponse {
int64 code = 1;
string message = 2;
Data data = 3;
}
message Data {
string version = 1;
google.protobuf.Value info = 2;
}
// 用于请求的数据
message AuthRequest{
string code =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
25
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
# 说明:
当数据中存在不确定数据时可以采用
google.protobuf.Value
来处理google.protobuf.Value
是Protocol Buffers
提供的一种通用类型,可以表示多种类型的数据。它可以用于处理以下类型的数据:- 基本数据类型:
null
、布尔值、整数(int32、int64)
、浮点数(float、double)
、字符串。 - 结构化数据类型:嵌套消息、字典
(Map)
。 - 列表和数组:列表中可以包含任意类型的数据,包括其他
google.protobuf.Value
类型的对象。
- 基本数据类型:
属性后面携带的值是字段标签
Field Tag
,Field Tag
必须在结构体内部唯一
# google.protobuf.Value
使用方法
- 在
protobuf
文件中引入google/protobuf/struct.proto
- 以上面例子为例
info
这个属性为不定向数据时,info
的数据类型为google.protobuf.Value info
# 生成 protobuf
的 go
文件
在同级目录下写一个 shell
文件,变更 authInfo.proto
文件名即可
#!/bin/zsh
protoc --go_out=. --go-grpc_out=. --plugin=protoc-gen-go=/usr/local/go/bin/protoc-gen-go authInfo.proto
1
2
3
2
3
# 使用 http
处理 protobuf
交互
不要问我都用上了
protobuf
为啥还用落后的http
交互...主要原因就是我懒,以及目前没时间涉及的太深,毕竟国内开发者懂的都懂,能用就行
⚠️ 两边均要将上面的
.proto
文件和.sh
文件放入项目中,并且生成protobuf
代码
# 发送请求
本代码中包含了请求和获取两部分
func ProtoHttpBasicConn(serviceUrl, nodeCode string) (string, error) {
// 编码
codeSerialization := &protoInfo.AuthRequest{Code: nodeCode}
// 序列化
pbRequestData, err := proto.Marshal(codeSerialization)
if err != nil {
fmt.Println("BasicConn proto.Marshal error:", err)
return "", err
}
// 发送请求
req, err := http.NewRequest(http.MethodPost, serviceUrl, bytes.NewBuffer(pbRequestData))
if err != nil {
fmt.Println("BasicConn http.NewRequest error:", err)
return "", err
}
// 设置请求头
req.Header.Set("Content-Type", "application/octet-stream") // 根据需要设置正确的内容类型
// 发送请求
client := http.Client{}
resp, err := client.Do(req)
if err != nil {
fmt.Println("发送请求失败:%v", err)
return "", err
}
defer resp.Body.Close()
// 读取响应
pbResponseData, err := io.ReadAll(resp.Body)
if err != nil {
fmt.Println("BasicConn io.ReadAll error:", err)
return "", err
}
// 反序列化返回数据
pbResponse := &protoInfo.AuthInfoResponse{}
err = proto.Unmarshal(pbResponseData, pbResponse)
if err != nil {
fmt.Println("BasicConn proto.Unmarshal error:", err)
return "", err
}
// 将返回的数据转换为字符串
return proto.CompactTextString(pbResponse), nil
}
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
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
# 服务端
// ...
// 省略接口部分,直接在内容中展示
pbRequestData, err := io.ReadAll(r.Request.Body)
if err != nil {
response.JsonExit(r, http.StatusInternalServerError, "error", err.Error())
}
// 反序列化返回数据
pbResponse := &protoInfo.AuthRequest{}
err = proto.Unmarshal(pbRequestData, pbResponse)
if err != nil {
response.JsonExit(r, http.StatusInternalServerError, "error", err.Error())
}
// proto转字符串
// fmt.Println(proto.CompactTextString(pbResponse))
// 创建一个 http.ResponseWriter 对象
writer := r.Response.Writer
pbResponseDataOriginal, err := proto.Marshal(&pbResponse)
// 设置返回数据
writer.Header().Set("Content-Type", "application/x-protobuf")
_, err = writer.Write(pbResponseDataOriginal)
// ...
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
# 使用 gRPC
处理 protobuf
交互
有空再写吧
# 错误经验
# protoc-gen-go: invalid Go import path "protoInfo" for "authInfo.proto"
出现 "protoc-gen-go: invalid Go import path" 的错误信息通常是由于在 .proto 文件中,指定的 Go import 路径不符合要求所致。
在 .proto
文件中增加 option go_package = "./protoInfo";
即可
# protoc-gen-go: unable to determine Go import path for "authInfo.proto"
这通常是由于 Protocol Buffers 编译器无法确定 Go 导入路径而引起的
在 .proto
文件中增加 option go_package = "./protoInfo";
即可
更新时间: 2023/6/29 16:58:19