Protobuf 中 any 的妙用

在使用 GRPC 时,常规的操作是将 message 定义好后进行数据传输,但总会遇到某些数据结构进行组合的操作,采用默认的定义 message 方式,造成代码量的激增。为了解决这个问题 protobuf 提供类型 any 解决 GRPC 中泛型的处理方式

目录结构

.
├── main.go
└── rpc
    ├── rsp.pb.go
    └── rsp.proto

首先,我们定义我们需要传输的消息

path project_dir/rpc/rsp.proto
采用 proto3 协议
定义 TestAny 用于测试 any 的动态传输
定义 Response 作为 GRPC 通用的消息交互

rsp.proto 内容

syntax = "proto3";

package rpc;

option go_package = ".;rpc";

import "google/protobuf/any.proto";

message TestAny {
  uint64 Id = 1;
  string Title = 2;
  string Content = 3;
}

message Response {
  uint32 Code = 1;
  string Msg = 2;
  google.protobuf.Any data = 3;
}

使用 protoc 编译工具,编译 rsp.proto,生成 rsp.pb.go 文件

path project_dir/rpc/rsp.pb.go
我们并不需要关注 rsp.pb.go 内部的所有内容
仅需要关注生成的消息体

> protoc --go_out=./ rsp.proto

rsp.pb.go 内容

通过 protoc 工具,生成了两个 struct,及为我们定义在 proto 文件中的 message

type TestAny struct {
	state         protoimpl.MessageState
	sizeCache     protoimpl.SizeCache
	unknownFields protoimpl.UnknownFields

	Id      uint64 `protobuf:"varint,1,opt,name=Id,proto3" json:"Id,omitempty"`
	Title   string `protobuf:"bytes,2,opt,name=Title,proto3" json:"Title,omitempty"`
	Content string `protobuf:"bytes,3,opt,name=Content,proto3" json:"Content,omitempty"`
}

type Response struct {
	state         protoimpl.MessageState
	sizeCache     protoimpl.SizeCache
	unknownFields protoimpl.UnknownFields

	Code uint32   `protobuf:"varint,1,opt,name=Code,proto3" json:"Code,omitempty"`
	Msg  string   `protobuf:"bytes,2,opt,name=Msg,proto3" json:"Msg,omitempty"`
	Data *any.Any `protobuf:"bytes,3,opt,name=data,proto3" json:"data,omitempty"`
}

测试使用 any

下面我们将演示实际场景中的应用
通过 ptypes.MarshalAny(marshal) 将我们定义的消息进行编码
通过 ptypes.UnmarshalAny(any, unmarshal) 对已经编码的消息进行反编码

main.go 内容

func main()  {
	marshal := &rpc.TestAny{
		Id:            1,
		Title:         "标题",
		Content:       "内容",
	}
	any, err := ptypes.MarshalAny(marshal)
	fmt.Println(any, err) // [type.googleapis.com/rpc.TestAny]:{Id:1 Title:"标题" Content:"内容"} <nil>

	msg := &rpc.Response{
		Code: 0,
		Msg:  "success",
		Data: any,
	}
	fmt.Println(msg) // Msg:"success" data:{[type.googleapis.com/rpc.TestAny]:{Id:1 Title:"标题" Content:"内容"}}

	unmarshal := &rpc.TestAny{}
	err = ptypes.UnmarshalAny(msg.Data, unmarshal)
	fmt.Println(unmarshal, err) // Id:1 Title:"标题" Content:"内容" <nil>
}
在Python使用protobuf的Any类型,你需要先定义和编译两个.proto文件,并使用protoc命令生成对应的Python代码。你可以使用以下命令来编译这两个.proto文件: protoc --python_out=. TransportMessage.proto protoc --python_out=. WeChatOnlineNoticeMessage.proto 接下来,你可以在Python代码使用protobuf的Any类型。通过在.proto文件定义Any字段,并使用pack和unpack函数来序列化和反序列化任意类型的数据。 在序列化时,你可以使用pack函数将数据打包成Any类型。例如,假设你有一个message对象msg,你可以使用以下代码将其打包成Any类型的数据: any_message = Any() any_message.Pack(msg) 在反序列化时,你可以使用unpack函数将Any类型的数据解包成原始类型。例如,假设你有一个Any类型的数据any_message,你可以使用以下代码将其解包成原始类型: msg = Message() any_message.Unpack(msg) 注意,解包前需要先创建一个空的Message对象,用于存储解包后的数据。 需要注意的是,使用Any类型需要在.proto文件引入google.protobuf.Any和google.protobuf.AnyOptions。你可以在.proto文件添加以下内容: import "google/protobuf/any.proto"; import "google/protobuf/any_options.proto"; 这样就可以在.proto文件使用Any类型了。 总结起来,要在Python使用protobuf的Any类型,你需要: 1. 定义和编译.proto文件,生成对应的Python代码; 2. 在.proto文件引入google.protobuf.Any和google.protobuf.AnyOptions; 3. 在代码使用pack和unpack函数来序列化和反序列化任意类型的数据。 你可以根据以上步骤来使用protobuf的Any类型。希望对你有所帮助!如果你还有其他问题,请随时提问。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值