Web 开发中没有哪个主题比 Representational State Transfer(简称 REST)更令人困惑了。这个术语来自于 Roy Fielding 在 U.C. Irvine 的博士论文的 第 5 章。
在这篇文章中,我们将回顾这一章,并为非学术的 Web 开发者总结重要概念。该论文内容密集,涉及大量与正式博士论文写作无关的技术术语,这些术语对非学术人士并不相关。
读完这篇文章后,你应该对 REST 有更好的理解,特别是 统一接口 的概念。
首先要了解 REST 的是,它是对原始 Web 的描述。Fielding 将 REST 描述为“分布式超媒体系统的架构风格”,这听起来很高端,但实际上就是我们所熟知的 Web:点击超链接、提交表单、查看图像、阅读段落等等。
它 并非 为 JSON API 的特定方法而创建,尽管如今大多数人听到 REST 时都是在这个上下文中。Fielding 描述的是早期的 Web,特别是它与早期客户端/服务器架构的区别。
不幸的是,在 5.1 节 中,Fielding 采用了从第一性原理推导 REST 的技术。这里我将总结每个小节,并在重要的部分澄清并添加上下文。
REST 当然是一种客户端-服务器架构,因为 Web 是一个客户端(浏览器)-服务器(HTTP 服务器)系统。
大多数开发者都知道,Web 被设计为无状态的。所有请求都应封装理解该请求所需的所有信息。例如,不应该有与一系列请求隐式关联的长时间运行的事务,就像你可能在 SQL 数据库会话中那样。
你可能知道,HTTP 有内置的 缓存机制。你现在不需要了解细节,但以后可以探索它。
在我看来,这一节是 REST 架构的核心,不幸的是它非常简短,因此我们将花一些时间扩展它,而不是只是总结它。本章开头写道:
REST 架构风格与其他基于网络的风格区别开来的核心特征是它强调组件之间的统一接口
为了澄清关于统一接口究竟是什么的讨论,让我们考虑一些简单的 HTML,我希望阅读本文的每个人都能理解:
<html>
<body>
<section>
<p>
Name: Joe Blow
</p>
<p>
Email: joe@blow.com
</p>
<p>
<a href="/contacts/42/edit">Edit</a>
<a href="/contacts/42/email">Email</a>
<a href="/contacts/42/archive">Archive</a>
</p>
</section>
</body>
</html>
这里我们有一个基本的 HTML 片段,包含一些 div、一些信息,然后是一些用于对联系人执行各种操作的锚标签。没什么复杂的。再说一次,为了讨论,想象这个内容可以在 http://example.com/contacts/42 找到。
回到论文:
REST 由四个接口约束定义:资源的识别;通过表示操纵资源;自描述消息;以及超媒体作为应用状态的引擎。
让我们逐一讨论这些。
REST 的第一个方面是 资源 的概念,这些资源可以通过…嗯,通用资源定位符(或 URL)在某处找到。请注意,HTML 包含了针对此资源(contacts/42)可以执行的操作的额外 URL,遵循 URL 路径的传统层次结构。
这听起来很高端,但它只是意味着你可以通过各种表示(即 HTML 页面)来更新和修改资源(即联系人),而不是必须发出 SQL 等来修改它。
这是 REST 的一个关键概念。请注意,在这个客户端-服务器设置中,浏览器(即客户端)对联系人一无所知。然而,它只需渲染服务器返回的 HTML 就能渲染出“联系人 UI”。消息本身完全是自描述的,包含客户端所需的所有信息,包括数据以及对该数据可能执行的操作(以链接形式)。
现在,将此与相同数据的 JSON 表示进行对比:
{
"name" : "Joe Blow",
"email" : "joe@example.com"
}
显然,这更小,但使用此数据的客户端必须决定两个关键事情:
第一部分通常使用客户端模板完成。第二部分通常通过阅读 API 文档并直接在客户端中编码与服务器的交互来完成。
这就是 REST-ful 系统与传统客户端-服务器系统的核心区别:在 REST-ful 系统中,客户端(即浏览器)对资源一无所知,它只知道如何渲染超媒体。在客户端-服务器系统中,关于资源的知识嵌入在客户端中。
两种方法各有优缺点,但以早期 Web 形式出现的 REST-ful 方法被证明是极其可靠和灵活的。它将关于资源的巨大知识量隐藏在 HTML 的 统一接口 后面,因此客户端没有机会像厚客户端那样崩溃。
现在,你可能已经注意到,在过去十年中,Web 开发趋势已从 REST-ful 架构转向更传统的客户端-服务器设置,使用 JSON API。你可能还注意到,关于 API 版本控制、提供更通用的查询功能等的讨论和问题更多了。这并非偶然:当我们将浏览器转变为托管厚客户端应用程序的虚拟机时,我们正在失去 REST-ful 模型的灵活性。
这个最后一个概念与前一个概念相辅相成:客户端通过与超媒体本身中找到的 URL(通过表单和链接)交互来转换应用状态。因此,在上面的 HTML 示例中,编辑、发送邮件和归档联系人的能力都编码为 HTML 中的锚标签。如果某个操作不可用,或者一个新操作变得可用,它将以新的 HTML 片段形式返回,在页面刷新后。
这与厚客户端方法形成对比,例如,本地存储可能异步与后端同步,因此 HTML 不是应用状态的引擎,而更像是一种(有些不稳定的)UI 描述语言。
有些好笑的是,HATEOAS 的 Wikipedia 文章 使用了 JSON,这不是一种自然的超媒体。如果你愿意,你可以在 JSON 之上叠加一些 REST-ful 行为,但这在现实世界中很少有用,而且 HATEOAS 通常在 JSON API 中被忽略。这是有道理的,因为 JSON API 主要用于传统的客户端-服务器架构,并不特别适合 REST-ful 风格。
这就是 REST 的核心,也是这篇文章的核心。你可以继续阅读以获取更多关于 Fielding 论文的细节和分析,但这里的核心要点是,REST-ful 超媒体架构与传统客户端-服务器架构之间存在鲜明区别,而这种区别主要围绕统一接口的概念,特别是它们的自描述性质。
再次,不要被这里的行话所困扰,只需思考这个 HTML 及其灵活性和独创性的奇迹:
<html>
<body>
<div>
<div>
Name: Joe Blow
</div>
<div>
Email: joe@blow.com
</div>
<div>
<a href="/contacts/42/edit">Edit</a>
<a href="/contacts/42/email">Email</a>
<a href="/contacts/42/archive">Archive</a>
</div>
</div>
</body>
</html>
你不需要了解太多关于这个的内容,除了 CDN 存在,并且你应该使用它们。
同样,你不需要了解太多关于这个的内容,除了 JavaScript 存在,并且它是唯一可选的部分。
我不会像之前其他节那样深入探讨这一节,因为它变得相当技术性,而且坦白说,有些无聊和重复(正如人们对博士论文的预期)。这一节的两个主要想法是资源和表示。
摘自论文:
REST 中信息的键抽象是一个资源。任何可以命名的信息都可以是资源:文档或图像、临时服务(例如“洛杉矶今天的天气”)、其他资源的集合、非虚拟对象(例如一个人)等等。
实际上,资源是任何可以用 URL 寻址的东西。当你访问 URL 时会发生什么?
嗯,你会得到该资源的 表示,以 HTTP 响应的形式,可能包含 HTML、指令等等。
我没有发现这一节有很多实际用途。其中有一些关于控制数据、媒体类型等方面的内容,这些最终在需要时都值得学习,但不是 Web 开发的常用方面。
剩余的 5.2 节同样没有为通用开发者提供太多内容。
这已成为一种模式,我再次觉得这一节对普通 Web 开发者没有太多有用的新信息,只有一个重大例外:它阐述了 REST 的好处。
摘自论文:
REST 的客户端-服务器关注点分离简化了组件实现,减少了连接器语义的复杂性,提高了性能调优的有效性,并增加了纯服务器组件的可扩展性。分层系统约束允许在通信的各种点引入中介——代理、网关和防火墙——而无需更改组件之间的接口,从而允许它们协助通信翻译或通过大规模共享缓存提高性能。REST 通过将消息约束为自描述来启用中间处理:请求之间交互是无状态的,使用标准方法和媒体类型来表示语义和交换信息,并且响应明确表示可缓存性。
这一切都是真实的,这就是为什么 Web 如此成功,并且将继续成功。
这些简短的节对对 REST 感兴趣的非学术人士并不相关。
这就是了,对 Roy Fielding 博士论文第 5 章的简要导览,该章赋予了我们 REST 这个术语。我重点关注了我认为对 Web 开发者最重要的领域,并试图传达 REST 如何描述原始 Web 模型。在我看来,统一接口概念是 REST 最重要和最有趣的方面,对于 Web 开发者来说理解它很有用,因为它主要负责上述好处。
最后,我希望你能看出 REST 对于描述当今大多数使用的 JSON API 是多么不合适。