是什么让JSON或YAML语法能够"through the wire"发送?


require 'yaml'
class Person
attr_accessor :name, :age
end
fred = Person.new
fred.name = "Fred Bloggs"
fred.age = 45
laura = Person.new
laura.name = "Laura Smith"
laura.age = 23
test_data = [ fred, laura ]
puts test_data.to_yaml
#YAML
- !ruby/object:Person
age: 45
name: Fred Bloggs
- !ruby/object:Person
name: Laura Smith
age: 23

这是我正在阅读的一本书中的 YAML 序列化示例。我无法理解是什么使 YAML 语法与普通的 ruby 代码有任何不同,以便保存/发送它。如果要像"二进制序列化"一样将其转换为二进制,那对我来说是有意义的,因为它可以更快地发送。如果序列化的目的是保持对象的状态有序并使其成为流,为什么不将其设置为原始顺序和语法的流呢?

关于二进制序列化是否会更快的问题:是的,它会。如果您担心速度,YAML 不是您想要的工具——您应该转向其他工具,例如 Cap'n Proto。YAML 被设计为人类可读的。

那么为什么要发送 YAML 而不是 Ruby 代码呢?好吧,对于初学者:安全性。如果一端将 Ruby 代码发送到另一端并在那里评估代码,如果未经授权的第三方找到将消息注入此流的方法,则很容易变成漏洞;它可能导致任意代码执行。

因此,让我们假设我们实际上不想发送任意的 Ruby 代码。相反,我们想要发送一个子集,它是一个计算出我们想要发送的数据的单个表达式。顺便说一下,这就是JSON的诞生方式:作为JavaScript的一个子集,计算为对象值。

由于 JSON 已经存在,因此基于一些序列化语言再次发明轮子是没有意义的,除非您想添加 JSON¹ 中缺少的某些功能。您需要编写一个完整的解析器和发射器(请注意,您不能简单地使用 Ruby 实现,因为如上所述,这将允许攻击者执行任意代码(。JSON 已经在各种编程语言和生态系统中得到支持,如果您重视跨平台兼容性,它将成为理想的数据交换格式。

所以现在的问题仍然是 YAML 除了 JSON 之外还提供了什么。有些人认为YAML语法比JSON,YMMV更具可读性。但是 YAML 中有许多功能使其优于 JSON:

  • YAML 具有可扩展的标记系统,用于具有某种类型的注释内容。代码示例:!ruby/object:Person.这可确保如果数据结构中存在可能出现不同类型值的字段,接收端会立即知道使用哪种类型进行反序列化。在 JSON 中,您需要类型推断(从表达式的值推断类型(来做出该决定,但这并不总是可能的²。
  • 数据结构可能包含循环(例如环列表、强连接图(。这些很难序列化。YAML 具有内置的锚点和别名,因此可以引用以前启动的节点来表示循环结构。JSON没有这样的东西。我认为如果不添加与 Ruby 本身不同的功能,就很难在基于 Ruby 的序列化语言中包含此功能。
  • 最后,这也是标题中问题的答案,YAML 专为流式传输而设计(JSON 程度要小得多(。YAML 流可以包含任意数量的文档。这使得保持流打开并等待接收端的新数据成为可能。相比之下,JSON 希望输入在一个对象之后结束。

所有这些并不意味着YAML(或JSON(是唯一的出路。数据中没有任何周期或异构字段?您不需要锚点/别名或标签!不需要人类可读的序列化?你可以使用二进制格式!JSON和YAML之所以成功,是因为它们的功能集很好地反映了许多应用程序中的需求。它是否适合您的应用程序由您决定。


¹ 肯定有一些项目出于各种原因正是这样做的。我想说的是,一般来说,实现正确的(反(序列化是一项涉及的任务,您通常希望使用已经存在的内容。

² 当然,您可以扩展 JSON 架构,以便每个节点都具有如下结构:

{
"type": "myType",
"value": ...
}

但这会使序列化非常冗长。

相关内容

最新更新