如何在 protobuf 消息中表示 UUID?

How do I represent a UUID in a protobuf message?

我想将 UUID 附加到我的 protobuf 用户消息示例中的字段。

message User {
  // field containing id as UUID type
  required string email;
  optional string name;
}

我知道protobuf消息还不支持UUID类型。我读过最好的方法是使用 UUID 消息类型。

所以我猜我的用户消息会导入我的 UUID 消息原型定义并将其用作字段类型,如下所示:

import "myproject/UUID.proto";

message User {
  required UUID id;
  required string email;
  optional string name;
}

我的问题是,UUID 消息将如何显示,我将如何 encode/decode 它?我的目标是 Java/Scala 和 C# 兼容性。

您可能应该使用 stringbytes 来表示 UUID。如果将 UUID 保持为人类可读的格式(例如 "de305d54-75b4-431b-adb2-eb6b9e546014")最方便,请使用 string,如果要存储 128 位原始值,请使用 bytes。 (如果您不确定,您可能想要 string。)

将值包装在名为 UUID 的消息类型中有助于使代码更加自我记录,但会产生一些性能开销,因此并非严格要求。如果你想这样做,定义类型如下:

message UUID {
  required string value = 1;
}

或:

message UUID {
  required bytes value = 1;
}

如果有的话,您想使用 string 来避免字节顺序问题。请注意,具有相同字符串表示形式(因此相同 "id")的 UUID 和 MS GUID 具有不同的字节流顺序(big-endian 与 little-endian)。如果您在协议中使用 bytes 在使用 UUID 的 Java 和使用 System.Guid 的 C# 之间进行通信,您最终可能会得到颠倒的 ID。

我没有足够的声誉点数来发表评论,所以我必须写这个作为答案。

使用字符串,而不是字节数组,这与其他一些评论者所说的不同。根据 MS (https://docs.microsoft.com/en-us/dotnet/architecture/grpc-for-wcf-developers/protobuf-data-types),“不要为 Guid 值使用字节字段。当 Protobuf 与其他平台交互时,字节顺序问题(维基百科定义)可能导致不稳定的行为,例如 Java ."

如果您想确保直接的互操作性,我建议使用字符串编码而不是字节编码:

message UUID {
  required string value = 1;
}

字节编码的问题是:不同的 UUID 库对字节使用不同的 encoding/decoding 方案,但它们同意如何 encode/decode 字符串。

例如,请参阅 C# 的 System.guid.toBytesArray returns 混合端格式:前三个组件采用小端编码,而后两个组件采用大端编码。

在Java中,Apache Commons Library Uuid.toRawBytes returns大端编码的uuid:

"String": 35918bc9-196d-40ea-9779-889d79b753f0
"C#"    : C9 8B 91 35 6D 19 EA 40 97 79 88 9D 79 B7 53 F0
"Java"  : 35 91 8B C9 19 6D 40 EA 97 79 88 9D 79 B7 53 F0

附带说明:Python 3 的 Uuid 提供两种编码:bytes 用于大端编码,bytes_le 用于混合端编码。