ProtoJSON 格式

介绍如何使用 Protobuf 到 JSON 的转换工具。

Protobuf 支持一种规范的 JSON 编码,从而更容易与不支持标准 protobuf 二进制线格式的系统共享数据。

ProtoJSON 格式不如 protobuf 线格式高效。转换器在编码和解码消息时会消耗更多 CPU,并且(除极少数情况外)编码后的消息会占用更多空间。此外,ProtoJSON 格式会将您的字段和枚举值名称放入编码消息中,这使得将来更改这些名称变得更加困难。移除字段是一项破坏性更改,会触发解析错误。简而言之,Google 几乎所有地方都更倾向于使用标准线格式而非 ProtoJSON 格式,原因有很多。

本主题稍后的表格按类型描述了编码方式。

将 JSON 编码的数据解析为协议缓冲区时,如果某个值缺失或其值为 null,则会被解释为相应的默认值。单一字段的多个值(使用重复或等效的 JSON 键)会被接受,并且最后一个值将被保留,这与二进制格式解析类似。请注意,并非所有 protobuf JSON 解析器实现都符合规范,某些不符合规范的实现可能会拒绝重复的键。

从协议缓冲区生成 JSON 编码输出时,如果 protobuf 字段具有默认值且该字段不支持字段存在性,则默认情况下会从输出中省略。实现可以提供选项来在输出中包含具有默认值的字段。

已设置值且支持字段存在性的字段始终会在 JSON 编码输出中包含其字段值,即使该值是默认值。例如,使用 optional 关键字定义的 proto3 字段支持字段存在性,如果设置了值,则始终会出现在 JSON 输出中。任何版本的 protobuf 中的消息类型字段都支持字段存在性,如果设置了值,则会出现在输出中。Proto3 隐式存在标量字段仅在其值不等于该类型的默认值时才会出现在 JSON 输出中。

在 JSON 文件中表示数字数据时,如果从线格式解析的数字不适合相应的类型,您将得到与在 C++ 中将数字强制转换为该类型时相同的效果(例如,如果将一个 64 位数字读取为 int32,它将被截断为 32 位)。

下表显示了数据在 JSON 文件中的表示方式。

ProtobufJSONJSON 示例注意
消息对象{"fooBar": v, "g": null, ...}生成 JSON 对象。消息字段名称被映射为 lowerCamelCase 并成为 JSON 对象键。如果指定了 json_name 字段选项,则使用指定的值作为键。解析器接受 lowerCamelCase 名称(或由 json_name 选项指定的名称)以及原始 proto 字段名称。对于所有字段类型,null 都是可接受的值,并被视为相应字段类型的默认值。但是,null 不能用于 json_name 值。有关更多信息,请参阅json_name 的更严格验证
枚举字符串"FOO_BAR"使用 proto 中指定的枚举值名称。解析器同时接受枚举名称和整数值。
map<K,V>对象{"k": v, ...}所有键都转换为字符串。
repeated V数组[v, ...]null 被接受为空列表 []
布尔值true, falsetrue, false
字符串字符串"Hello World!"
字节base64 字符串"YWJjMTIzIT8kKiYoKSctPUB+"JSON 值是将数据使用标准 base64 编码(带填充)编码为字符串。接受标准或 URL 安全的 base64 编码(带或不带填充)。
int32, fixed32, uint32数字1, -10, 0JSON 值将是十进制数字。数字或字符串都可接受。空字符串无效。
int64, fixed64, uint64字符串"1", "-10"JSON 值将是十进制字符串。数字或字符串都可接受。空字符串无效。
float, double数字1.1, -10.0, 0, "NaN", "Infinity"JSON 值将是数字或特殊的字符串值之一:"NaN"、"Infinity" 和 "-Infinity"。数字或字符串都可接受。空字符串无效。指数表示法也接受。
Any对象{"@type": "url", "f": v, ... }如果 Any 包含具有特殊 JSON 映射的值,它将按如下方式转换:{"@type": xxx, "value": yyy}。否则,该值将被转换为 JSON 对象,并插入 "@type" 字段以指示实际数据类型。
Timestamp字符串"1972-01-01T10:00:20.021Z"使用 RFC 3339,生成的输出总是 Z 标准化,并使用 0、3、6 或 9 位小数。也接受除 "Z" 之外的偏移量。
Duration字符串"1.000340012s", "1s"生成的输出始终包含 0、3、6 或 9 位小数,取决于所需的精度,后跟后缀 "s"。接受任何小数位数(也可以没有),只要它们符合纳秒精度,并且后缀 "s" 是必需的。
Struct对象{ ... }任何 JSON 对象。请参阅 struct.proto
包装器类型各种类型2, "2", "foo", true, "true", null, 0, ...包装器在 JSON 中使用与被包装原始类型相同的表示,不同之处在于允许 null 并在数据转换和传输过程中保留。
FieldMask字符串"f.fooBar,h"请参阅 field_mask.proto
ListValue数组[foo, bar, ...]
Value任何 JSON 值。查看google.protobuf.Value 了解详细信息。
NullValuenullJSON null
Empty对象{}一个空的 JSON 对象

JSON 选项

符合规范的 protobuf JSON 实现可能提供以下选项

  • 始终输出无存在性字段:默认情况下,不支持存在性且具有其默认值的字段会在 JSON 输出中省略(例如,值为 0 的隐式存在整数,空字符串的隐式存在字符串字段,以及空的 repeated 和 map 字段)。实现可以提供一个选项来覆盖此行为,并输出带有默认值的字段。

    截至 v25.x,C++、Java 和 Python 实现不符合规范,因为此标志影响 proto2 的 optional 字段,但不影响 proto3 的 optional 字段。计划在未来版本中修复此问题。

  • 忽略未知字段:默认情况下,protobuf JSON 解析器应拒绝未知字段,但可以提供选项以在解析时忽略未知字段。

  • 使用 proto 字段名而非 lowerCamelCase 名称:默认情况下,protobuf JSON 打印器应将字段名转换为 lowerCamelCase 并将其用作 JSON 名称。实现可以提供一个选项来改用 proto 字段名作为 JSON 名称。Protobuf JSON 解析器必须同时接受转换后的 lowerCamelCase 名称和 proto 字段名。

  • 将枚举值输出为整数而非字符串:默认情况下,JSON 输出使用枚举值的名称。可以提供一个选项来改用枚举值的数字值。