Protocol Buffers 常用类型

google.protobuf 包的 API 文档。

索引

以“Value”结尾的常用类型是其他类型的包装消息,例如 BoolValueEnumValue。这些现在已过时。今天使用包装器的唯一原因是

  • 与已使用它们的消息的线路兼容性。
  • 如果您想将标量值放入 Any 消息中。

在大多数情况下,有更好的选择

  • 对于新消息,最好使用常规的显式存在字段(proto2/proto3 中的 optional,版本 >= 2023 中的常规字段)。
  • 扩展通常是比 Any 字段更好的选择。

Any

Any 包含任意序列化的消息以及描述序列化消息类型的 URL。

JSON

Any 值的 JSON 表示形式使用反序列化嵌入消息的常规表示形式,并带有一个附加字段 @type,其中包含类型 URL。示例

package google.profile;
message Person {
  string first_name = 1;
  string last_name = 2;
}
{
  "@type": "type.googleapis.com/google.profile.Person",
  "firstName": <string>,
  "lastName": <string>
}

如果嵌入的消息类型是众所周知的并且具有自定义 JSON 表示形式,则该表示形式将被嵌入,添加一个字段 value,除了 @type 字段之外,该字段还包含自定义 JSON。示例 (对于消息 google.protobuf.Duration)

{
  "@type": "type.googleapis.com/google.protobuf.Duration",
  "value": "1.212s"
}
字段名称Type描述
type_urlstring

URL/资源名称,其内容描述了序列化消息的类型。

对于使用 schema httphttps 或无 schema 的 URL,以下限制和解释适用

  • 如果未提供 schema,则假定为 https
  • URL 路径的最后一段必须表示类型的完全限定名称(如 path/google.protobuf.Duration)。
  • 对 URL 的 HTTP GET 必须生成二进制格式的 google.protobuf.Type 值,或产生错误。
  • 允许应用程序根据 URL 缓存查找结果,或将它们预编译为二进制文件以避免任何查找。因此,需要在类型更改时保持二进制兼容性。(使用版本化的类型名称来管理重大更改。)

除了 httphttps(或空 schema)之外的 Schema 可以与特定于实现的语义一起使用。

valuebytes必须是上述指定类型的有效序列化数据。

Api

Api 是协议缓冲区服务的轻量级描述符。

字段名称Type描述
namestring此 API 的完全限定名称,包括包名称,后跟 API 的简单名称。
methodsMethod此 API 的方法,顺序未指定。
optionsOption附加到 API 的任何元数据。
versionstring

此 API 的版本字符串。如果指定,则必须具有 major-version.minor-version 形式,如 1.10。如果省略次版本,则默认为零。如果整个版本字段为空,则主版本从包名称派生,如下所述。如果该字段不为空,则将验证包名称中的版本是否与此处提供的版本一致。

版本控制 schema 使用 语义版本控制,其中主版本号表示重大更改,次版本号表示附加的、非重大更改。两个版本号都是向用户发出的信号,表明对不同版本的期望,应根据产品计划仔细选择。

主版本也反映在 API 的包名称中,该名称必须以 v<major-version> 结尾,如 google.feature.v1。对于主版本 0 和 1,可以省略后缀。零主版本只能用于实验性的、非 GA API。

source_contextSourceContext此消息表示的协议缓冲区服务的源上下文。
mixinsMixin包含的 API。请参阅 Mixin
syntaxSyntax服务的源语法。

BoolValue

bool 的包装消息。

BoolValue 的 JSON 表示形式是 JSON truefalse

字段名称Type描述
valueboolbool 值。

BytesValue

bytes 的包装消息。

BytesValue 的 JSON 表示形式是 JSON 字符串。

字段名称Type描述
valuebytesbytes 值。

DoubleValue

double 的包装消息。

DoubleValue 的 JSON 表示形式是 JSON 数字。

字段名称Type描述
valuedoubledouble 值。

Duration

Duration 表示有符号的、固定长度的时间跨度,表示为秒数和纳秒分辨率的秒的小数。它独立于任何日历和“天”或“月”之类的概念。它与 Timestamp 相关,因为两个 Timestamp 值之间的差是 Duration,并且可以从 Timestamp 中添加或减去。范围约为 +-10,000 年。

示例 1:在伪代码中从两个时间戳计算 Duration。

Timestamp start = ...;
Timestamp end = ...;
Duration duration = ...;

duration.seconds = end.seconds - start.seconds;
duration.nanos = end.nanos - start.nanos;

if (duration.seconds < 0 && duration.nanos > 0) {
  duration.seconds += 1;
  duration.nanos -= 1000000000;
} else if (duration.seconds > 0 && duration.nanos < 0) {
  duration.seconds -= 1;
  duration.nanos += 1000000000;
}

示例 2:在伪代码中从时间戳 + Duration 计算时间戳。

Timestamp start = ...;
Duration duration = ...;
Timestamp end = ...;

end.seconds = start.seconds + duration.seconds;
end.nanos = start.nanos + duration.nanos;

if (end.nanos < 0) {
  end.seconds -= 1;
  end.nanos += 1000000000;
} else if (end.nanos >= 1000000000) {
  end.seconds += 1;
  end.nanos -= 1000000000;
}

Duration 的 JSON 表示形式是一个 String,它以 s 结尾以指示秒,并且前面是秒数,纳秒表示为秒的小数。

字段名称Type描述
secondsint64时间跨度的有符号秒数。必须在 -315,576,000,000 到 +315,576,000,000 之间,包括端点。
nanosint32时间跨度的纳秒分辨率的秒的有符号小数。小于 1 秒的持续时间用 0 seconds 字段和正或负 nanos 字段表示。对于 1 秒或更长时间的持续时间,nanos 字段的非零值必须与 seconds 字段的符号相同。必须在 -999,999,999 到 +999,999,999 之间,包括端点。

Empty

通用的空消息,您可以重复使用它以避免在 API 中定义重复的空消息。一个典型的例子是将其用作 API 方法的请求或响应类型。例如

service Foo {
  rpc Bar(google.protobuf.Empty) returns (google.protobuf.Empty);
}

Empty 的 JSON 表示形式是空 JSON 对象 {}

Enum

枚举类型定义

字段名称Type描述
namestring枚举类型名称。
enumvalueEnumValue枚举值定义。
optionsOption协议缓冲区选项。
source_contextSourceContext源上下文。
syntaxSyntax源语法。

EnumValue

枚举值定义。

字段名称Type描述
namestring枚举值名称。
numberint32枚举值编号。
optionsOption协议缓冲区选项。

Field

消息类型的单个字段。

字段名称Type描述
kindKind字段类型。
cardinalityCardinality字段基数。
numberint32字段编号。
namestring字段名称。
type_urlstring字段类型 URL,不带 schema,用于消息或枚举类型。示例:"type.googleapis.com/google.protobuf.Timestamp"
oneof_indexint32Type.oneofs 中字段类型的索引,用于消息或枚举类型。第一个类型的索引为 1;零表示该类型不在列表中。
packedbool是否使用备用打包线路表示形式。
optionsOption协议缓冲区选项。
json_namestring字段 JSON 名称。
default_valuestring此字段的默认值的字符串值。仅限 Proto2 语法。

Cardinality

字段是可选的、必需的还是重复的。

枚举值描述
CARDINALITY_UNKNOWN对于基数未知的字段。
CARDINALITY_OPTIONAL对于可选字段。
CARDINALITY_REQUIRED对于必需字段。仅限 Proto2 语法。
CARDINALITY_REPEATED对于重复字段。

Kind

基本字段类型。

枚举值描述
TYPE_UNKNOWN字段类型未知。
TYPE_DOUBLE字段类型 double。
TYPE_FLOAT字段类型 float。
TYPE_INT64字段类型 int64。
TYPE_UINT64字段类型 uint64。
TYPE_INT32字段类型 int32。
TYPE_FIXED64字段类型 fixed64。
TYPE_FIXED32字段类型 fixed32。
TYPE_BOOL字段类型 bool。
TYPE_STRING字段类型 string。
TYPE_GROUP字段类型 group。仅限 Proto2 语法,且已弃用。
TYPE_MESSAGE字段类型 message。
TYPE_BYTES字段类型 bytes。
TYPE_UINT32字段类型 uint32。
TYPE_ENUM字段类型 enum。
TYPE_SFIXED32字段类型 sfixed32。
TYPE_SFIXED64字段类型 sfixed64。
TYPE_SINT32字段类型 sint32。
TYPE_SINT64字段类型 sint64。

FieldMask

FieldMask 表示一组符号字段路径,例如

paths: "f.a"
paths: "f.b.d"

此处 f 表示某些根消息中的字段,ab 表示在 f 中找到的消息中的字段,d 表示在 f.b 中的消息中找到的字段。

字段掩码用于指定应由 get 操作(projection)返回或由 update 操作修改的字段子集。字段掩码还具有自定义 JSON 编码(请参见下文)。

投影中的字段掩码

FieldMask 指定 projection 时,API 将过滤响应消息(或子消息),使其仅包含掩码中指定的那些字段。例如,考虑以下“预掩码”响应消息

f {
  a : 22
  b {
    d : 1
    x : 2
  }
  y : 13
}
z: 8

在应用上一个示例中的掩码后,API 响应将不包含字段 x、y 或 z 的特定值(它们的值将设置为默认值,并在 proto 文本输出中省略)

f {
  a : 22
  b {
    d : 1
  }
}

除非在字段掩码的最后一个位置,否则不允许重复字段。

如果 get 操作中不存在 FieldMask 对象,则该操作将应用于所有字段(就像已指定所有字段的 FieldMask 一样)。

请注意,字段掩码不一定适用于顶级响应消息。在 REST get 操作的情况下,字段掩码直接应用于响应,但是在 REST list 操作的情况下,掩码而是应用于返回资源列表中的每个单独消息。在 REST 自定义方法的情况下,可以使用其他定义。掩码的应用位置将在 API 中的声明中明确记录。在任何情况下,对返回资源/资源的影响都是 API 的必需行为。

更新操作中的字段掩码

更新操作中的字段掩码指定将要更新的目标资源的哪些字段。API 必须仅更改掩码中指定的字段的值,而保持其他字段不变。如果传入资源来描述更新后的值,则 API 将忽略掩码未涵盖的所有字段的值。

为了将字段的值重置为默认值,该字段必须在掩码中,并在提供的资源中设置为默认值。因此,为了重置资源的所有字段,请提供资源的默认实例并在掩码中设置所有字段,或者不提供如下所述的掩码。

如果在更新时不存在字段掩码,则该操作将应用于所有字段(就像已指定所有字段的字段掩码一样)。请注意,在 schema 演变的情况下,这可能意味着客户端不知道并且因此未填充到请求中的字段将被重置为默认值。如果这是不需要的行为,则特定服务可能需要客户端始终指定字段掩码,否则会产生错误。

与 get 操作一样,请求消息中描述更新值的资源的位置取决于操作类型。在任何情况下,API 都必须遵守字段掩码的效果。

HTTP REST 的注意事项

使用字段掩码的更新操作的 HTTP 类型必须设置为 PATCH 而不是 PUT,以满足 HTTP 语义(PUT 只能用于完全更新)。

字段掩码的 JSON 编码

在 JSON 中,字段掩码编码为单个字符串,其中路径用逗号分隔。每个路径中的字段名称都转换为/从 lower-camel 命名约定转换而来。

作为示例,请考虑以下消息声明

message Profile {
  User user = 1;
  Photo photo = 2;
}
message User {
  string display_name = 1;
  string address = 2;
}

在 proto 中,Profile 的字段掩码可能如下所示

mask {
  paths: "user.display_name"
  paths: "photo"
}

在 JSON 中,相同的掩码表示如下

{
  mask: "user.displayName,photo"
}
字段名称Type描述
pathsstring字段掩码路径集。

FloatValue

float 的包装消息。

FloatValue 的 JSON 表示形式是 JSON 数字。

字段名称Type描述
valuefloatfloat 值。

Int32Value

int32 的包装消息。

Int32Value 的 JSON 表示形式是 JSON 数字。

字段名称Type描述
valueint32int32 值。

Int64Value

int64 的包装消息。

Int64Value 的 JSON 表示形式是 JSON 字符串。

字段名称Type描述
valueint64int64 值。

ListValue

ListValue 是值重复字段的包装器。

ListValue 的 JSON 表示形式是 JSON 数组。

字段名称Type描述
valuesValue动态类型值的重复字段。

Method

Method 表示 API 的方法。

字段名称Type描述
namestring此方法的简单名称。
request_type_urlstring输入消息类型的 URL。
request_streamingbool如果为 true,则请求是流式的。
response_type_urlstring输出消息类型的 URL。
response_streamingbool如果为 true,则响应是流式的。
optionsOption附加到该方法的任何元数据。
syntaxSyntax此方法的源语法。

Mixin

声明要包含在此 API 中的 API。包含 API 必须重新声明包含 API 中的所有方法,但是文档和选项的继承方式如下

  • 如果在剥离注释和空格后,重新声明的方法的文档字符串为空,则将从原始方法继承。

  • 将继承服务配置(http,可见性)的每个注释,这些注释未在重新声明的方法中设置。

  • 如果继承了 http 注释,则路径模式将按如下方式修改。任何版本前缀都将替换为包含 API 的版本加上指定的 root 路径(如果指定)。

简单 mixin 的示例

package google.acl.v1;
service AccessControl {
  // Get the underlying ACL object.
  rpc GetAcl(GetAclRequest) returns (Acl) {
    option (google.api.http).get = "/v1/{resource=**}:getAcl";
  }
}

package google.storage.v2;
service Storage {
  //       rpc GetAcl(GetAclRequest) returns (Acl);

  // Get a data record.
  rpc GetData(GetDataRequest) returns (Data) {
    option (google.api.http).get = "/v2/{resource=**}";
  }
}

mixin 配置的示例

apis:
- name: google.storage.v2.Storage
  mixins:
  - name: google.acl.v1.AccessControl

mixin 构造意味着 AccessControl 中的所有方法也在 Storage 中以相同的名称和请求/响应类型声明。文档生成器或注释处理器将在继承文档和注释后看到有效的 Storage.GetAcl 方法,如下所示

service Storage {
  // Get the underlying ACL object.
  rpc GetAcl(GetAclRequest) returns (Acl) {
    option (google.api.http).get = "/v2/{resource=**}:getAcl";
  }
  ...
}

请注意,路径模式中的版本如何从 v1 更改为 v2

如果在 mixin 中指定了 root 字段,则它应该是继承的 HTTP 路径所在的相对路径。示例

apis:
- name: google.storage.v2.Storage
  mixins:
  - name: google.acl.v1.AccessControl
    root: acls

这意味着以下继承的 HTTP 注释

service Storage {
  // Get the underlying ACL object.
  rpc GetAcl(GetAclRequest) returns (Acl) {
    option (google.api.http).get = "/v2/acls/{resource=**}:getAcl";
  }
  ...
}
字段名称Type描述
namestring包含的 API 的完全限定名称。
rootstring如果非空,则指定继承的 HTTP 路径的根路径。

NullValue

NullValue 是一个单例枚举,用于表示 Value 类型联合的空值。

NullValue 的 JSON 表示形式是 JSON null

枚举值描述
NULL_VALUE空值。

Option

协议缓冲区选项,可以附加到消息、字段、枚举等。

字段名称Type描述
namestring选项的名称。例如,"java_package"
valueAny选项的值。例如,"com.google.protobuf"

SourceContext

SourceContext 表示有关 protobuf 元素的来源的信息,例如定义它的文件。

字段名称Type描述
file_namestring包含关联的 protobuf 元素的 .proto 文件的路径限定名称。例如:"google/protobuf/source.proto"

StringValue

string 的包装消息。

StringValue 的 JSON 表示形式是 JSON 字符串。

字段名称Type描述
valuestringstring 值。

Struct

Struct 表示结构化数据值,由映射到动态类型值的字段组成。在某些语言中,Struct 可能受本机表示形式支持。例如,在 JS 等脚本语言中,结构表示为对象。该表示形式的详细信息与该语言的 proto 支持一起描述。

Struct 的 JSON 表示形式是 JSON 对象。

字段名称Type描述
fieldsmap<string, Value>动态类型值的映射。

Syntax

定义协议缓冲区元素的语法。

枚举值描述
SYNTAX_PROTO2语法 proto2
SYNTAX_PROTO3语法 proto3

Timestamp

Timestamp 表示独立于任何时区或日历的时间点,以 UTC Epoch 时间的纳秒分辨率的秒和秒的小数表示。它使用 Proleptic Gregorian Calendar 进行编码,该日历将 Gregorian 日历向后扩展到一年。它被编码为假定所有分钟均为 60 秒长,即“涂抹”闰秒,因此不需要闰秒表进行解释。范围从 0001-01-01T00:00:00Z 到 9999-12-31T23:59:59.999999999Z。通过限制在该范围内,我们确保可以与 RFC 3339 日期字符串相互转换。请参阅 https://www.ietf.org/rfc/rfc3339.txt

Timestamp 类型在 RFC 3339 格式中编码为字符串:“{year}-{month}-{day}T{hour}:{min}:{sec}[.{frac_sec}]Z”,其中 {year} 始终使用四位数字表示,而 {month}{day}{hour}{min}{sec} 各自零填充为两位数字。小数秒(最多可达 9 位数字,即高达 1 纳秒分辨率)是可选的。“Z”后缀表示时区(“UTC”);时区是必需的。proto3 JSON 序列化器在打印 Timestamp 类型时应始终使用 UTC(如“Z”所示),并且 proto3 JSON 解析器应能够接受 UTC 和其他时区(如偏移量所示)。

示例 1:从 POSIX time() 计算时间戳。

Timestamp timestamp;
timestamp.set_seconds(time(NULL));
timestamp.set_nanos(0);

示例 2:从 POSIX gettimeofday() 计算时间戳。

struct timeval tv;
gettimeofday(&tv, NULL);

Timestamp timestamp;
timestamp.set_seconds(tv.tv_sec);
timestamp.set_nanos(tv.tv_usec * 1000);

示例 3:从 Win32 GetSystemTimeAsFileTime() 计算时间戳。

FILETIME ft;
GetSystemTimeAsFileTime(&ft);
UINT64 ticks = (((UINT64)ft.dwHighDateTime) << 32) | ft.dwLowDateTime;

// A Windows tick is 100 nanoseconds. Windows epoch 1601-01-01T00:00:00Z
// is 11644473600 seconds before Unix epoch 1970-01-01T00:00:00Z.
Timestamp timestamp;
timestamp.set_seconds((INT64) ((ticks / 10000000) - 11644473600LL));
timestamp.set_nanos((INT32) ((ticks % 10000000) * 100));

示例 4:从 Java System.currentTimeMillis() 计算时间戳。

long millis = System.currentTimeMillis();

Timestamp timestamp = Timestamp.newBuilder().setSeconds(millis / 1000)
    .setNanos((int) ((millis % 1000) * 1000000)).build();

示例 5:从 Python 中的当前时间计算时间戳。

now = time.time()
seconds = int(now)
nanos = int((now - seconds) * 10**9)
timestamp = Timestamp(seconds=seconds, nanos=nanos)
字段名称Type描述
secondsint64表示自 Unix 纪元 1970-01-01T00:00:00Z 以来的 UTC 时间秒数。必须在 0001-01-01T00:00:00Z 到 9999-12-31T23:59:59Z 之间,包括端点。
nanosint32纳秒分辨率的秒的非负小数。具有小数的负秒值仍然必须具有向前计时的非负纳秒值。必须在 0 到 999,999,999 之间,包括端点。

Type

协议缓冲区消息类型。

字段名称Type描述
namestring完全限定的消息名称。
fieldsField字段列表。
oneofsstring此类型的 oneof 定义中出现的类型列表。
optionsOption协议缓冲区选项。
source_contextSourceContext源上下文。
syntaxSyntax源语法。

UInt32Value

uint32 的包装消息。

UInt32Value 的 JSON 表示形式是 JSON 数字。

字段名称Type描述
valueuint32uint32 值。

UInt64Value

uint64 的包装消息。

UInt64Value 的 JSON 表示形式是 JSON 字符串。

字段名称Type描述
valueuint64uint64 值。

Value

Value 表示动态类型的值,可以是 null、数字、字符串、布尔值、递归结构值或值列表。值的生产者应设置其中一个变体,缺少任何变体表示错误。

Value 的 JSON 表示形式是 JSON 值。

字段名称Type描述
联合字段,仅限以下之一
null_valueNullValue表示空值。
number_valuedouble表示双精度值。请注意,尝试序列化 NaN 或 Infinity 会导致错误。(我们不能像对常规字段那样将它们序列化为字符串“NaN”或“Infinity”值,因为它们将被解析为 string_value,而不是 number_value)。
string_valuestring表示字符串值。
bool_valuebool表示布尔值。
struct_valueStruct表示结构化值。
list_valueListValue表示重复的 Value