Merge pull request #260 from haifeiWu/master

修改部分翻译不准确的问题
This commit is contained in:
YIN, Gang 2022-08-09 12:18:33 +08:00 committed by GitHub
commit dee7f4bff3
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

20
ch4.md
View File

@ -26,11 +26,11 @@
* 向后兼容 (backward compatibility)
新代码可以读旧数据。
代码可以读取由代码编写的数据。
* 向前兼容 (forward compatibility)
旧代码可以读新数据。
代码可以读取由数据编写的数据。
向后兼容性通常并不难实现:新代码的作者当然知道由旧代码使用的数据格式,因此可以显示地处理它(最简单的办法是,保留旧代码即可读取旧数据)。
@ -76,8 +76,8 @@
JSONXML 和 CSV 属于文本格式,因此具有人类可读性(尽管它们的语法是一个热门争议话题)。除了表面的语法问题之外,它们也存在一些微妙的问题:
* **数numbers** 的编码多有歧义之处。XML 和 CSV 不能区分数字和字符串(除非引用一个外部模式)。 JSON 虽然区分字符串与数值,但不区分整数和浮点数,而且不能指定精度。
* 当处理更大的数值时,这个问题显得尤为严重。例如大于 $2^{53}$ 的整数无法使用 IEEE 754 双精度浮点数精确表示,因此在使用浮点数(例如 JavaScript的语言进行分析时这些数字会变得不准确。 Twitter 有一个关于大于 $2^{53}$ 的数字的例子,它使用 64 位整数来标识每条推文。 Twitter API 返回的 JSON 包含了两种推特 ID一种是 JSON 数值,另一种是十进制字符串,以避免 JavaScript 程序无法正确解析数字的问题【10】。
* **数numbers** 编码有很多模糊之处。在 XML 和 CSV 中,无法区分数字和碰巧由数字组成的字符串(除了引用外部模式)。 JSON 虽然区分字符串与数字,但并不区分整数和浮点数,并且不能指定精度。
* 这在处理大数字时是个问题。例如大于 $2^{53}$ 的整数无法使用 IEEE 754 双精度浮点数精确表示,因此在使用浮点数(例如 JavaScript的语言进行分析时这些数字会变得不准确。 Twitter 有一个关于大于 $2^{53}$ 的数字的例子,它使用 64 位整数来标识每条推文。 Twitter API 返回的 JSON 包含了两个推特 ID一个是 JSON 数字,另一个是十进制字符串,以解决 JavaScript 程序中无法正确解析数字的问题【10】。
* JSON 和 XML 对 Unicode 字符串(即人类可读的文本)有很好的支持,但是它们不支持二进制数据(即不带 **字符编码 (character encoding)** 的字节序列)。二进制串是很有用的功能,人们通过使用 Base64 将二进制数据编码为文本来绕过此限制。其特有的模式标识着这个值应当被解释为 Base64 编码的二进制数据。这种方案虽然管用,但比较 Hacky并且会增加三分之一的数据大小。
* XML 【11】和 JSON 【12】都有可选的模式支持。这些模式语言相当强大所以学习和实现起来都相当复杂。 XML 模式的使用相当普遍,但许多基于 JSON 的工具才不会去折腾模式。对数据的正确解读(例如区分数值与二进制串)取决于模式中的信息,因此不使用 XML/JSON 模式的应用程序可能需要对相应的编码 / 解码逻辑进行硬编码。
* CSV 没有任何模式,因此每行和每列的含义完全由应用程序自行定义。如果应用程序变更添加了新的行或列,那么这种变更必须通过手工处理。 CSV 也是一个相当模糊的格式如果一个值包含逗号或换行符会发生什么。尽管其转义规则已经被正式指定【13】但并不是所有的解析器都正确的实现了标准。
@ -415,12 +415,12 @@ Web 服务仅仅是通过网络进行 API 请求的一系列技术的最新版
所有这些都是基于 **远程过程调用RPC** 的思想,该过程调用自 20 世纪 70 年代以来一直存在【42】。 RPC 模型试图向远程网络服务发出请求,看起来与在同一进程中调用编程语言中的函数或方法相同(这种抽象称为位置透明)。尽管 RPC 起初看起来很方便但这种方法根本上是有缺陷的【43,44】。网络请求与本地函数调用非常不同
* 本地函数调用是可预测的,并且成功或失败仅取决于受你控制的参数。网络请求是不可预知的:由于网络问题,请求或响应可能会丢失,或者远程计算机可能很慢或不可用,这些问题完全不在你的控制范围之内。网络问题是常见的,所以你必须预测他们,例如通过重试失败的请求。
* 本地函数调用要么返回结果,要么抛出异常,或者永远不返回(因为进入无限循环或进程崩溃)。网络请求有另一个可能的结果:由于超时,它可能会返回没有结果。在这种情况下,你根本不知道发生了什么:如果你没有得到来自远程服务的响应,你无法知道请求是否通过(我们将在 [第八章](ch8.md) 更详细地讨论这个问题)。
* 如果你重试失败的网络请求,可能会发生请求实际上正在通过,只有响应丢失。在这种情况下,重试将导致该操作被执行多次,除非你在协议中引入去重机制(**幂等**,即 idempotence。本地函数调用没有这个问题。 (在 [第十一章](ch11.md) 更详细地讨论幂等性)
* 每次调用本地功能时,通常需要大致相同的时间来执行。网络请求比函数调用要慢得多,而且其延迟也是非常可变的:好的时候它可能会在不到一毫秒的时间内完成,但是当网络拥塞或者远程服务超载时,可能需要几秒钟的时间完成一样的东西
* 调用本地函数时,可以高效地将引用(指针)传递给本地内存中的对象。当你发出一个网络请求时,所有这些参数都需要被编码成可以通过网络发送的一系列字节。如果参数是像数字或字符串这样的基本类型倒是没关系,但是对于较大的对象很快就会变成问题。
* 客户端和服务可以用不同的编程语言实现,所以 RPC 框架必须将数据类型从一种语言翻译成另一种语言。这可能会捅出大篓子,因为不是所有的语言都具有相同的类型 —— 例如回想一下 JavaScript 的数字大于 $2^{53}$ 的问题(请参阅 “[JSON、XML 和二进制变体](#JSON、XML和二进制变体)”)。用单一语言编写的单个进程中不存在此问题。
* 本地函数调用是可预测的,并且成功或失败仅取决于受你控制的参数。网络请求是不可预测的:请求或响应可能由于网络问题会丢失,或者远程计算机可能很慢或不可用,这些问题完全不在你的控制范围之内。网络问题很常见,因此必须有所准备,例如重试失败的请求。
* 本地函数调用要么返回结果,要么抛出异常,或者永远不返回(因为进入无限循环或进程崩溃)。网络请求有另一个可能的结果:由于超时,它返回时可能没有结果。在这种情况下,你根本不知道发生了什么:如果你没有得到来自远程服务的响应,你无法知道请求是否通过(我们将在 [第八章](ch8.md) 更详细地讨论这个问题)。
* 如果你重试失败的网络请求,可能会发生请求实际上已经完成,只是响应丢失的情况。在这种情况下,重试将导致该操作被执行多次,除非你在协议中建立数据去重机制(**幂等性**,即 idempotence。本地函数调用时没有这样的问题。 (在 [第十一章](ch11.md) 更详细地讨论幂等性)
* 每次调用本地函数时,通常需要大致相同的时间来执行。网络请求比函数调用要慢得多,而且其延迟也是非常可变的:好的时候它可能会在不到一毫秒的时间内完成,但是当网络拥塞或者远程服务超载时,可能需要几秒钟的时间才能完成相同的操作
* 调用本地函数时,可以高效地将引用(指针)传递给本地内存中的对象。当你发出一个网络请求时,所有这些参数都需要被编码成可以通过网络发送的一系列字节。如果参数是像数字或字符串这样的基本类型倒是没关系,但是对于较大的对象很快就会出现问题。
* 客户端和服务可以用不同的编程语言实现,所以 RPC 框架必须将数据类型从一种语言翻译成另一种语言。这可能会变得很丑陋,因为不是所有的语言都具有相同的类型 —— 例如回想一下 JavaScript 的数字大于 $2^{53}$ 的问题(请参阅 “[JSON、XML 和二进制变体](#JSON、XML和二进制变体)”)。用单一语言编写的单个进程中不存在此问题。
所有这些因素意味着尝试使远程服务看起来像编程语言中的本地对象一样毫无意义,因为这是一个根本不同的事情。 REST 的部分吸引力在于,它并不试图隐藏它是一个网络协议的事实(尽管这似乎并没有阻止人们在 REST 之上构建 RPC 库)。