背景
最近在开发一个网关项目, 需要将外部的 JSON 请求转换成 gRPC 请求向后转发, 并将 gRPC 响应转换为 JSON 格式的响应返回.
实现过程中发现使用 google.protobuf.json_format.MessageToDict
的时候 ( google.protobuf.json_format.MessageToJson
同理) 有一些需要注意留意的细节.
遇到问题
当使用 MessageToDict
对 messge 转换时, 发现两个不符合预期的问题:
- 如果一个 message field 对应的值为 zero value, 对应的
dict
中不会显示该键值对 - field 名称会从 snake_case 被转换成 lowerCamelCase
源码分析
以 MessageToDict
为例, 我们看一下函数的定义.
1 | def MessageToDict( |
所以自动忽略 zero value 和 field 转换分别是由 including_default_value_fields
和 preserving_proto_field_name
两个参数控制.
结论
在调用 MessageToDict
函数时, 将以上两个参数指定为 True
即可解决问题. 代码示例如下:
示例代码可以在这个项目中查看
思考
这个问题会令人在意的主要原因是因为 Python 是一个弱类型语言, 或许 protobuf 在传输和存储过程中, 为了考虑性能, 确实会用省略字段的方式来表达零值, 就像这个回答中说到的那样. 只要在将 protobuf 转换为特定语言的 struct 时再对应调整成恰当的结构就能满足需求, 但是在转换成 JSON 的时候默认将这个字段抹去, 我仍然认为是不合理的.
Reference
- python grpc package tutorial: https://grpc.io/docs/tutorials/basic/python/
- 关于 zero value 默认忽略的解释: https://github.com/protocolbuffers/protobuf/issues/2796