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