有这样一种任务场景:使用protobuf序列化数据,然后通过http协议将这个序列化的数据传输给服务器。这个过程倒是比较简单,只是其中有几个问题如果不搞明白的话,很可能在应用时会遇到麻烦而耽误比较长的时间。google推出了一款grpc倒是可以非常方便地使用protobuf作为通讯接口,只是在个人使用时,总会遇到不愿意使用grpc的情况。比如已经搭建好了一个网站,如果再加个grpc的服务端就需要多启动一个服务。这时,如果数据不太敏感,直接在http协议中作为参数传递给服务端是最简单省事的一种。本文就是在这样的背景下展开。
1. 定义和编译proto文件
首先创建一个proto文件,并定一个message。然后编译生成对应的python文件。

定义和编译proto文件
从编译产出可以看出,我们想要的python文件已经生成。
2. 存储数据并序列化
使用Person这个类型创建数据类型,并进行序列化。

创建数据并序列化
这里需要注意了,使用protobuf序列化得到的字符串是bytes类型的。这里有必要说明一个python中两种字符序列类型:str和bytes。其中bytes是一种字节流,一般从文件中以二进制方式读取的就是这种类型。这种类型数据的优点是效率高,缺点也很明显就是可读性很差。另一个str是一种unicode类型的字符串,可以表示世界上所有的文字和标点,可读性和通用型都很不错,一般我们使用的就是这个类型。原本在网络传输中是应该使用bytes类型的,毕竟可以节省带宽。本文这种背景下的任务是通过http参数完成的,而http参数是以字符串str的形式在请求链接中存在的。因此这就需要将bytes转换成str类型,然后构造到http链接最后的参数上。
那么就有一个很直观的思路,就是直接将bytes字符串转换成str字符串,然后拼接上去,这样虽然效率很低,但是不妨一试。

字符串类型转化
这个时候严重的问题就出现了:将bytes字符串解码成str字符串之后内容是不一样的,而且其中还很可能包含一些http链接中不允许出现的字符。甚至连这种decode函数执行也不一定会成功。多番尝试发现,这种方式行不通,必须用其他办法。
3. 使用base64生成字符串
使用base64进行编码protobuf序列化产生的bytes字符串。

base64编码
发现转换之后的类型还是bytes,所以需要进行一下decode的转化。还有一个问题是这种方式加密生成的字符串还是有可能包含http链接不允许的字符,比如:+/-,空格等等。所幸base64这个工具提供了一种解决这种问题的方式。

url安全的base64编码
这样得到的字符串就完全符合http参数传递的标准,然后通过 http://localhost?param=CBIVAAAqQx0AAHBCIghoZWxsby0wMQ== 就可以把字符串发送给服务器。
4. 服务器端的处理
在服务器端通过解析GET或者POST数据获取客户端传来的字符串,然后进行反序列化。

服务器端处理
可以看到解析成功,相关数据顺利传送到服务器端。到此就实现了通过http链接把protobuf数据传送到了服务器上。
本文的notebook版本文件会在GitHub上共享,感兴趣的可以在github上cnbluegeek/notebook下查看。