我可以取消一个必需的protobuf字段吗?

14

我有一个客户端-服务器应用程序,其中服务器以protobuf格式传输经序列化的对象到客户端,并且我想要去除一个required字段。不幸的是,我不能同时更改客户端和服务器来使用新的.proto定义。

如果我将一个required字段更改为optional,但仅在代码中序列化消息时更改(即反序列化代码未被重建,并且仍然认为它是required字段),我是否可以继续发布可被反序列化的消息只要我填充现在optional字段的值即可

(至少对于我尝试过的一些简单情况(仅使用Java),这样做似乎没问题,但我想知道它是否是一种通常明智的方法,以及是否存在任何需要担心的边缘情况等)。

动机:我的目标是在一个客户端-服务器应用程序中退役一个required字段,其中服务器发布由客户端反序列化的消息。我的打算的方法是:

  1. 在主干上将required字段更改为optional
  2. 如果需要部署新的服务器代码(用于其他功能/修复),请确保在消息中继续填充可选字段
  3. 逐步部署所有客户端的更新代码(这需要时间,因为它需要涉及到具有自己发布计划的其他团队)。
  4. 确认所有客户端都已更新。
  5. 开始退役(即不再填充)可选字段。

请注意,我知道protobuf文档中说“required is forever”,但对我来说,这意味着这是一种简化,因为它被限定为“将字段更改为可选字段将会有问题”-有问题,而不是不可能...! - bacar
这就是为什么我几乎总是将每个字段都设置为可选的原因之一,以防我们在未来更改布局... 我已经被这个特性咬了太多次了。 - g19fanatic
相关 https://dev59.com/B1wZ5IYBdhLWcg3wIdZ8 - TooTone
2个回答

22
根据编码格式文档,序列化字节流本身不会对字段是否必需进行编码。也就是说,optionalrequired在编码后的序列化消息中没有任何区别。使用Java生成的代码,我已经进行了实际确认,并将序列化消息写入磁盘并比较输出结果,其中包含了所有支持的原始类型和代表其他类型的字段。

3
只要字段被设置了,使用parseFrom(byte[])方法进行反序列化仍然有效,因为byte[]会保持不变。
然而,人们可能会想知道为什么要将字段从必需更改为可选,除非你准备好使它成为可选的?基本上,你只是在.proto文件中将其变为“可选”,但是通过始终填充它来强制要求它是必需的。这只是一个想法。

为了迎合那些还不知道该字段是可选的客户。如果我将其设置为可选并停止同时填充该字段(即在所有反序列化的客户端都意识到它可以是可选之前),则反序列化的客户端将会崩溃 - 这是不好的!(我可以尝试先更新所有客户端,但这需要我维护 .proto 的两个副本 - 一个用于客户端的“可选”,一个用于服务器的“必须”,而我等待所有客户端升级)。 - bacar
我想,如果您向不同的客户端发送不同的protobuf消息,那么这是有意义的。但是,如果服务器发布到一个主题,而所有客户端都连接到该主题,则我的问题仍然存在。如果任何一个客户端尚未更新以处理可选字段,则在protobuf中将其声明为可选的就没有任何意义。逐个更新客户端以处理它是可选的情况,然后在.proto中声明它是可选的会更有意义。 - CaTalyst.X
不,我并没有给不同的客户端发送不同的消息 - 实际上,如果我能够根据客户端版本定制消息,则此问题将是多余的。如果不在客户端使用的.proto中声明它为可选项,又如何“更新客户端以处理它是可选的”?如果您不更改客户端的.proto文件,则parseFrom会在字段丢失时抛出异常。 - bacar
也许你的问题的意思是,“为什么你要将字段从必填更改为可选,然后立即将这个毫无意义的更改部署到服务器上”。我已经更新了我的原始问题,以澄清我不打算这样做。如果这解决了你的疑虑,我们应该删除我们的评论 :-) - bacar

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接