REST系列详解REST架构风格 —— 带你阅读Web发展史上的一个重要技术文献
Posted 无数_mirage
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了REST系列详解REST架构风格 —— 带你阅读Web发展史上的一个重要技术文献相关的知识,希望对你有一定的参考价值。
文章目录
- Filding博士的REST论文(本文中所提到的“论文”一词,若无特殊说明均代指此论文)
- Architectural Styles and the Design of Network-based Software Architectures 原文
Fielding博士的REST论文中文版(中文版旧版-李琨主译)- ==架构风格与基于网络应用软件的架构设计(中文修订版)==(中文版-李琨2013年修订)
- REST深入剖析及实践策略研究(赵峰-2009年河北大学工学硕士学位论文)
- wiki-REST、中文wiki-REST
- 知乎-怎样用通俗的语言解释REST,以及RESTful?
REST详解
REST,是Roy Thomas Fielding博士于2000年在他的博士论文《Architectural Styles and the Design of Network-based Software Architectures》(架构风格与基于网络应用软件的架构设计)第5章提出的一种 为分布式超媒体系统设计的REST架构风格
(这篇论文以下简称"论文")
摘自论文
分布式:信息服务的提供商必须能够有能力满足无法控制的可伸缩性和软件组件的独立部署两方面的要求(上图述)。这促使他们采取分布式架构。REST共有6条架构约束,其中"无状态"约束最能体现出为分布式设计。
超媒体:超媒体就是通过超链接(URI)组合的多媒体信息(包括文本、图像、视频等)。人们日常使用的万维网(World Wide Web,简称web)是规模最大的超媒体系统,所有的web应用(如爱奇艺、网易云、百度、网盘等)也都是超媒体系统。
之所以Fielding专门说"超媒体系统"而非"web系统",是因为架构师们知道设计一个东西时应当具有抽象思维,这会让它们适用性更强,而不仅仅局限于某一个应用系统。但因为web始终是规模最大的超媒体系统,所以为了不让我们的思维绕弯子,可以统一认为REST是为web设计的。并且论文也包含了很多与web相关的内容,更是在第6章专门讲述如何将REST应用于Web
Fielding博士是HTTP协议(1.0版和1.1版)和URI等Web架构标准的主要设计者、也是Apache HTTP服务器的主要设计者、Apache基金会的第一任主席,他的这篇论文是Web发展史上的一个重要的技术文献。
词组解释
REST全称Representational State Transfer
(其它资料中有各种翻译,如 表现层状态传输、表现层状态转化 等)
论文译者李琨 将其翻译为"表述性状态移交"。对于这个翻译的理解,我与李琨老师专门进行了交流,最终认为理解为"状态表述的移交"或许更好。英文与中文的语序本就有不同,那些按照顺序翻译的释义并不能很好地表达出REST的意思
论文在讲到"表述"时,其实已经用白话解释了REST
最终结合起来,REST的正确释义应该是:(资源)状态表述的移交,资源是省略的主语。
该释义可以用括号分隔成 ((资源的状态)的表述)的移交
,方便更好地理解
可能会有人问:HTTP(Hyper Text Transfer Protocol)不是超文本传输协议吗,把REST的T翻译为传输不更好理解吗
实则不然。论文中提到 HTTP翻译为超文本"传输"协议是错误的,它应当是超文本"移交"协议。
REST对HTTP的开发起到了指导作用,所以HTTP的T也应该是移交的意思
详情见:HTTP 超文本移交协议
现在慢慢解释
①Resources 资源
REST的名称中,省略了主语,资源是REST对于信息的核心抽象
所谓"资源",就是网络上的一个实体,或者说是网络上的一个具体信息。它可以是一段文本、一张图片、一首歌曲,总之就是一个具体的实在。你可以用一个URI(统一资源定位符)指向它。每个资源对应一个特定的URI,要获取这个资源,访问它的URI就可以,因此URI就成了每一个资源的地址或独一无二的识别符。
所谓"上网",就是与互联网上一系列的"资源"互动,调用它的URI。
②State 状态
资源的状态,即资源的信息,包括资源的属性和内容。比如这个资源存不存在、是什么时候创建的、内容是什么,这都属于资源的状态
③Representations 表述
representation
翻译为"表述"非常之信达雅,比常用的表象、表现都更好。
REST的R是
representational
,是representation
的形容词形式,李琨把它翻译为"表述性",其实这个翻译让人感觉有些别扭,不那么好理解。我认为它更多的是为了迁就representation
的翻译,即"表述"为名词,则"表述性"为它的形容词
所以不必过于纠结"表述性"这个翻译,重点其实在于它的名词representation
论文也专门对representations
进行了解释
“使用表述来捕获某个资源的状态”,理解为 表述是资源状态的一种具象表现形式
表述由一个字节序列(二进制流,所有的信息都以二进制流进行传输)和描述这些字节的表述元数据构成,它是资源状态的具象化信息
(我认为) 基于rest风格的http的数据包的主要内容就是表述。例如
- 请求获取某个资源内容,响应体表述了资源当前的状态
- 请求修改某个资源内容,与此相关的 URL、请求方法(POST)、请求体(表示了修改的内容) 表述了资源要被修改的状态
- 请求删除某个资源内容,与此相关的 URL、请求方法(DELETE) 表述了资源要被删除的状态
这些http包含的信息不是真正的资源,而是表述了资源的某一时刻的状态
④Transfer 移交/转移
资源状态的表述在web的各个组件中移交。
在REST的中文版初版,Transfer被翻译为转移。2013修订版中,改为了移交。这两个翻译的意义比较接近,"移交"可能更细致严谨,但"转移"更顺口。其实无论用哪一个都不会造成理解上的偏差
⑤Representational State Transfer
最终理解
(摘自李琨-什么是资源?什么是资源的表述?)
客户端应用与资源的交互,是通过资源的 “representation”(表述) 来间接完成的。资源的表述是一段对于资源(在某个特定时刻的)状态的描述。
客户端请求资源的表述,对表述加以修改,然后将修改过的表述发送给服务器端,请求服务器端对资源执行某种(局部的或者完全的)状态改变。
在客户端-服务器端之间转移的,并不是资源本身,而是资源的表述。缩写词REST中的“state transfer”翻译为“状态转移”,在客户端-服务器端之间转移的资源表述,所代表的正是资源的当前状态。
资源的表述,可以有多种格式,例如json/xml/html/纯文本等等。服务器发送给客户端的资源表述的格式,可以通过定义在HTTP协议中的标准的内容协商(content negotiation)机制来确定。
论文摘要
摘自论文中的《论文摘要》
REST架构约束
REST架构约束在第5章进行描述,这也是整篇论文的重点
如上图标识处,这是一个混合架构风格,所以以下约束并不全是REST所特有的 (REST区别于其他架构风格的核心特征是第四个约束-统一接口)。
这个混合架构风格中的几种风格约束,除REST特有的之外,都在第3章进行了详细描述,每条非特有约束在论文中也明确指出了是取自第3章的描述中的哪一个风格
一、Client–server:客户端-服务器
论文原文 5.1.2 Client-server
3.4.1小节
“客户端-服务器”,即C/S架构,它表示客户端和服务器是两台分立的机器,这在基于网络的应用的架构风格中最为常见
在Web工程上,用的最多的客户端是浏览器,也就是B/S架构,它也属于C/S架构,是C/S的变种。
网络是基于C/S架构的,这条约束重在表示REST是一个网络风格的架构,同时强调分离用户界面和数据存储这两个关注点,使组件可以独立进化。
论文这段话最不好理解的是 “改善了用户界面跨多个平台的可移植性”。我尝试解读一下
可移植性是指,如果计算机程序可以在创建它的操作系统以外的操作系统中使用而无需进行重大返工,则可移植性是一种计算机程序的特性。移植是完成使计算机程序在新环境中运行所需的任何工作的任务。
跨平台移植最典型的当属java(一次编写、到处运行)。用户界面跨平台移植意味着,用户界面也可以做到一次编写就能部署到多个平台。这将促使客户端与服务器分离,且要求客户端具备相当的独立进化能力。然后,C/S的联系仅仅依靠网络接口,只要不改变接口,二者可以任意进化。
如今的跨平台用户界面开发框架有:Flutter、electron、uniapp等等
与这个约束相对的,即非C/S架构,客户端和服务器不是分立的机器。非C/S可以理解为(参考知乎):在电脑上用某视频播放器看本地磁盘上的电影。这就不是C/S架构,它和网络没有任何关系
二、Stateless:无状态
论文原文 5.1.3 Stateless
3.4.3小节
客户端负责维护应用状态和会话状态,服务器维护资源状态。
通信必须在本质上是无状态的,因此从客户到服务器的每个请求都必须包含理解该请求所必需的所有信息,不能利用任何存储在服务器上的上下文,会话状态要全部保存在客户端,服务器端根据这些状态信息来处理请求。
这个约束产生了可见性、可靠性和可伸缩性三个架构属性,使分布式系统更加健壮。但也因为设计上的权衡 而存有一些不那么重要的缺点(不需要考虑)
优点
- visibility:可见性、透明度。系统无需通过请求内容以外的信息判断请求的完整内容
- reliability:可靠性、稳定度。在部分失败的情况下,减轻了恢复的难度
- scalability:可伸缩性、伸缩度。无需储存请求间的状态使服务器端可以很快释放资源并简化实现。增加了水平拓展的便利性
缺点
- 降低网络性能:因为请求需要传送额外的数据,让服务器能足够理解这个请求。比如每次都要带那么一堆Request-Header
- 降低服务器对于同种请求进行处理的控制能力:“将应用状态放在客户端还降低了服务器
对于一致的应用行为的控制能力,因为这样一来,应用就得依赖于跨多个客户端版本
(semantics across multiple client versions)的语义的正确实现” 这句话经过了一些思考和讨论,也没有明白作者的意思。(如果有大神理解可以放在评论中) 不过即使不理解这个缺点,也完全不妨碍理解REST,因为在设计的权衡点中,缺点是次要的
三、Cacheability:缓存
论文原文 5.1.4 Cacheability
客户端和中间的通讯传递者可以将服务器的回复缓存起来。回复必须明确的或者间接的表明本身是否可以进行缓存,这可以预防客户端在将来进行请求的时候得到陈旧的或者不恰当的数据。管理良好的缓存机制可以减少客户端-服务器之间的交互,甚至完全避免客户端-服务器交互,这进一步提了高性能和可扩展性。
————
以上几条约束都取自 已有的web架构风格,接下来就是REST特有的、对早期Web架构进行扩展的约束
四、⭐Uniform Interface:统一接口 (RESTful API)
论文原文 5.1.5 Uniform Interface
这是REST的核心特征
这条约束引出了"四个接口架构约束",它们可以实现所有组件之间统一的接口,可以指导组件的行为、简化整个系统架构并提高交互的可见性(透明度)。
①资源的识别:接口能够标识客户端和服务器交互中涉及的特定资源。例如使用URI标识资源
②通过表述来操作资源:客户端得到资源的表述时,能够有足够的信息来修改或删除服务器上的资源,如果它有权这么做的话。
③自描述的消息:每个消息都包含足够的信息来描述该消息 以支持中间组件的处理。例如HTTP使用标准的方法(PUT|DELETE…)和媒体类型(content-type)来表达语义和交换信息。响应还可以明确地表示其可缓存性(Cache-Control)。
摘自5.3.1小节
6.3.2小节还有对HTTP自描述信息的更详细描述
④超媒体作为应用程序状态的引擎(HATEOAS):请求REST资源返回的表述不仅包含资源数据,还包含指向其它相关资源的超链接。这样一来,REST的应用程序(客户端)只需要硬编码一个初始的URI,就可以动态地使用服务器返回的超链接来发现它需要的所有可用资源。HATEOAS实现了用超媒体(超链接)驱动客户端的状态(用户进行的操作),HATEOAS提供了资源的可发现性。简单地说,客户端完全通过服务器动态提供的响应与RESTAPI进行交互。说的更简单些,你不需要任何文档或其它外部信息来使用REST API
这四个接口约束,体现出了REST面向资源的核心思想(很像Unix"一切皆文件"的哲学思想)。
本节描述的接口,就是我们平时所说的 RESTful API
————
HATEOAS的详细解释
HATEOAS更简单的意思是 用超链接(超媒体的核心是超链接)驱动客户端的状态
客户端状态。可以理解为 受用户的行为产生的客户端属性。例如当用户触发某个链接,客户端的界面就随之发生了变化,这也叫做客户端的状态随之发生了变化。界面是最直观的肉眼可见的状态,但状态不只包含界面。
这些可使用的链接是服务器动态响应到客户端的,而不需要用户输入或客户端硬编码。当所有的接口都这么做,那么整个客户端状态就实现了超链接驱动
类比。HATEOAS类似于人类web用户访问网站的主页(REST的客户端就像浏览器),用户只需要记住主页的地址,就可以通过主页展示的各个超链接进一步访问网站的资源。
作用。HATEOAS最重要的一个作用是松耦合。如果REST服务的调用者需要对所有资源URI进行硬编码,那么这些URI与程序是紧耦合的。而HATEOAS实现的动态URI与程序是松耦合的。
示例。wiki-hateoas中有一个典型的示例。客户端请求一个账户信息的接口,不仅会获得账户详情,还会获得一组href,它包括存款、提款、转账等URI。如果账户已透支,则href只包含存款。
// REQUEST
GET bank.example.com/accounts/12345 HTTP/1.1
// RESPONSE
HTTP/1.1 200 OK
"account":
"account_number": 12345,
"balance":
"currency": "usd",
"value": 100.00
,
"links":
"deposits": "/accounts/12345/deposits",
"withdrawals": "/accounts/12345/withdrawals",
"transfers": "/accounts/12345/transfers",
"close-requests": "/accounts/12345/close-requests"
// RESPONSE (overdrawn)
HTTP/1.1 200 OK
"account":
"account_number": 12345,
"balance":
"currency": "usd",
"value": -25.00
,
"links":
"deposits": "/accounts/12345/deposits"
应用。spring提供了一个HATEOAS框架:Spring HATEOAS、指南-构建超媒体驱动的 RESTful Web 服务
缺点。
- 缺乏安全性。客户端根据响应来动态地调用后续API,但这么做具有盲目性、不可控性,也就意味着不安全性。你的客户端不能保证能够适配现在以及以后的API,你不能保证充分测试,因为它们是动态的。如果服务器对客户端是不可信的,那么动态API会更加危险。
- 无法丰富描述。随着web的发展,某些API可能无法依靠这种简单的方式调用,比如微信/支付宝/PayPal的支付接口,他们需要提供图文文档来让调用者理解和掌握这套API。
- 所以目前HATEOAS并不流行(我没有发现有哪个系统使用了HATEOAS)。当然,也可能是人们还未发现让HATEOAS变得可靠易用的方案
五、Layered System:分层系统
论文原文 5.1.6 Layered System
3.4.2小节
论文对这条约束描述的很细致。
分层系统带来了客户端和服务器的中间组件(简称中间件),如代理、网关、web服务器、消息中间件、缓存服务等。它们能够为客户端与服务器的交互带来帮助,如提供负载均衡、安全性检查、消息缓存等等。
很多中间件都发展成了成熟的开源项目,系统架构开发中经常会用到。
分层系统简化了每个组件的实现,为整个系统的复杂性设置了边界,提高了系统的可伸缩性。和CS约束(第一条约束)一样,这种分层更进一步增强了各组件的独立进化。
分层系统的唯一缺点是 增加了数据处理的开销(要经过多个组件) 和 组件通信带来的延迟,因此降低了用户感受到的性能。如果系统架构能够支持缓存,可以通过缓存来弥补这个缺点。
六、Code-On-Demand:按需代码 (可选)
论文原文 5.1.7 Layered System
3.5.3小节
这条约束表示 服务器可以向REST客户端添加拓展功能,通过发送可由该客户端执行的代码。例如 客户端脚本,如javascript;或编译的组件,如Java applet。
举个例子来更好地理解这一点。
例如,一个网络浏览器就像一个REST客户端,服务器传递HTML内容,浏览器进行渲染。在服务器端,有某种服务器端语言,在服务器端执行一些逻辑工作。但是,如果我们想添加一些在浏览器中工作的逻辑,那么我们(作为服务器端开发者)可以向客户端和浏览器发送一些JavaScript代码,然后执行这些JavaScript …
这种做法能够为一个已部署的客户添加功能,提升可扩展性和可配置性。但它降低了系统的可见性(透明度),如果客户端无法信任服务器,这会导致明显的客户端安全问题。所以这是REST可选的约束。
什么是RESTful?
ful是形容词后缀,RESTful
表示REST式、REST形式的、REST样子的
任何遵守REST约束的系统都被称为RESTful(Rest式)架构
wiki-REST (这里在描述上仅限定于Web服务是不客观的)
Roy Thomas Fielding 博士 (作者简介)
“Fielding的这篇论文是Web发展史上的一个重要的技术文献,值得每一位web乃至internet工作者阅读。”—— 如果仅仅这么说,大家可能并不会在意它。
为了让我们重视REST,知道它的价值。就不得不了解论文的作者 —— Roy Fielding
这是Fielding的个人网站:Roy T. Fielding
自1993年以来,Fielding一直积极参与万维网项目。他建立了最初的UCI-ICS的万维网服务器,创建了一些万维网软件包(libwww-ada95、libwww-perl、MOMspider、wwwstat)
并在1994年初通过IETF的URI、HTTP和HTML(用于检索和查看本文档的一组协议)工作组参与了指定和改进万维网基础设施的工作。成为了URI和HTTP(HTTP1.0和HTTP1.1)的主要设计者
Fielding还是Apache基金会的第一任董事会主席,是Apache HTTP服务器的主要设计者。Apache HTTP服务器如今在在web服务器中依然占主导地位。
当然,Fielding还创作了这篇论文,即《Architectural Styles and the Design of Network-based Software Architectures》(架构风格与基于网络应用软件的架构设计)。这篇论文主要研究现代网络架构设计的原理,以及它与其他建筑风格的不同之处。
因此Fielding博士可谓是Web架构的奠基者之一。
REST论文,其实就是Fielding以Web设计者的视角,描述了Web架构应该是什么样子的。在论文的最后一章(第六章),Fielding还描述了把REST应用到HTTP和URI这两个Web最重要的技术。
REST与Web、HTTP、URI
论文的最后一章(第六章) 描述了 把REST应用于HTTP和URI两个Web规范。
HTTP和URI是Web的两大重要技术。REST是为超媒体系统设计的架构,Web是最大的超媒体系统。所以将REST应用于HTTP和URI是非常有必要的论题
下图划出了第六章的一些重点,可以快速领悟REST和Web的联系
可见,REST论文虽然是2000年发表的,但实际上在1994年就已经被构思出来,用于指导Web架构规范的设计和开发,并在这些实践中不断地迭代和完善。
2000年这个时间点也值得琢磨,因为它正好是HTTP1.1发布的一年后(HTTP1.1在1999年发布)。让人不自觉联想:或许这表示REST和HTTP都已经走向了成熟阶段。
REST应用于URI的体现:REST 对于信息的核心抽象是资源。REST为URI规范定义了"资源"这个术语,以至于URI的设计与REST的"资源标识符"这个架构概念相匹配。
这几句话都来自论文
REST应用于HTTP的体现:REST的约束体现在HTTP中
REST约束 | HTTP |
---|---|
CS | 网络是基于C/S的,C/S是网络协议最基础的特性,HTTP是网络协议 |
无状态 | HTTP是无状态的协议 |
缓存 | HTTP1.1新增了缓存处理cache-control 字段。通过设置字段cache-control来控制缓存。当浏览器请求资源时,先看是否有缓存的资源,如果有缓存,直接取,不会再发请求,如果没有缓存,则发送请求。 |
统一接口 | 资源的识别:HTTP使用URL标识资源 自描述的消息:HTTP1.1新增了五种请求方法OPTIONS、PUT、PATCH、DELETE、TRACE 、 CONNECT 用于实现自描述的消息 |
————
总结:REST是为超媒体系统设计的架构,Web是最大的超媒体系统。HTTP和URI是Web的两大重要技术,REST指导了HTTP和URI的设计和开发。如此形成了一个闭环设计,最终构成了如今的Web
RESTful API 设计
使REST架构风格区别于其它基于网络的架构风格的核心特征的是 REST的第四条约束 “统一接口”(Uniform Interface)。它强调了所有组件之间要有一个统一的接口。这个接口可以指导组件的行为、简化整个系统架构并提高交互的可见性(透明度)。
这个"统一接口",就发展成了今天的 RESTful API,即REST风格的接口。
RESTful API 有一个非常精辟的解释:就是用URL定位资源,用HTTP动词(GET|PUT|POST|DELETE|...
)描述对资源的操作
这句话非常适合入门者快速领悟并运用 RESTful API 。
Richardson Maturity Model
“用URL定位资源,用HTTP动词描述对资源的操作”。这句话非常适合入门者快速领悟并运用 RESTful API 。普通玩家可以止步于此了,专业玩家请继续。
但句话的确精辟,但不是RESTful API的全部。熟读论文的朋友应该知道,REST的统一接口约束引出了四条接口架构约束,分别是:资源的标识、通过表述来操作资源、自描述的消息、超媒体作为应用状态的引擎(HATEOAS)。"用URL定位资源,用HTTP动词描述对资源的操作"显然没有做到全部
于是我们引出 Richardson Maturity Model (RMM) 理查森成熟度模型。
该模型来自于 2008年11月20日,Leonard Richardson在QCon的演讲Justice Will Take Us Millions Of Intricate Moves的第三幕The Maturity Heuristic。
后来被Matin Fowler进行了进一步地、更简洁的的解释(原文-Richardson Maturity Model),并把它叫做 Richardson Maturity Model
RMM根据Web API对模型四个层次的遵守和符合情况进行分类,该模型的研究是为了找出REST和其他形式的网络服务之间的制约关系。
该模型将RESTful设计的原则部分分为三个步骤:资源识别(URI)、HTTP动词和超媒体控制(HATEOAS)。
RMM可以用来确定一个Web服务架构对REST原则的遵守程度,特别是评估RESTful Web API设计的质量。它将Web API分为四个级别(从0到3),每一个更高的级别都对应着对REST设计的更全面的遵守,下一个级别也包含了前一个级别的所有特征。
第一层 | Level 0: The Swamp of POX (POX沼泽)
这是该模型的起点。它仅仅使用HTTP作为远程交互的通信隧道。本质上,这个层级所做的是使用HTTP作为远程过程调用(RPC)的一种具体形式。
这是一个简单直接的RPC风格的系统,消息的传递是以POX(Plain Old XML)、JSON或其它文本格式进行的。
(LV0的名字中仅提到了POX,而没有JSON或其它文本格式。可能是因为当时主流XML格式,比较典型的是SOAP)
Lv0层级的系统不归类于RESTful
第二层 | Level 1: Resources (资源)
在RMM中实现REST的第一步是引入"资源",URL是资源的抽象标识。因此,现在我们不再向一个单一的服务端点发起请求,而是开始与各个资源对话。
这与单纯的RPC产生了区别,就像是编程语言中的面向过程和面向对象。引入资源后,请求不再是单纯调用一些函数并传递参数,而是在一个特定的对象(资源)上调用一个方法,为其它信息提供参数。
这是一种思维的转变。REST对信息的核心抽象是资源,Web组件的交互就是对资源的操作
第三层 | Level 2: HTTP Verbs (HTTP动词)
从这层开始使用HTTP动词和HTTP响应码进行交互,使其接近于HTTP本身的使用方式。
HTTP的请求动词,最常用的有四个
- GET:用于获取资源。比如查询用户信息
- POST:用于创建资源。比如创建用户
- PUT:用于更新资源。比如更新用户信息
- DELETE:用于删除资源。比如删除用户
HTTP的响应码,常见得有
- 200:表示请求成功
- 302:表示重定向
- 403:表示没有权限访问
- 404:表示找不到URL对应的资源
- 500:表示服务器出错了,完成不了这次请求
正确地使用HTTP请求动词和响应码是至关重要的。比如,HTTP将GET定义为一种安全操作,即它不会对任何东西的状态做任何重大改变。这允许我们以任何顺序安全地调用GET,每次都能得到相同的结果(只要资源不发生改变)。这样做的重要作用是,它允许请求路由中的任何参与者(组件、Web基础设施)使用缓存,这是使网络表现良好的一个关键因素。通过遵守HTTP的规则,我们能够利用这种能力。
第四层 | Level 3: Hypermedia Controls (超媒体控制)
最后一层介绍了超媒体控制,即实现HATEOAS,这在前面描述REST"统一接口"时有详细介绍(如果记不清应该回去再看一遍)
请求REST资源返回的表述不仅包含资源数据,还包含指向其它相关资源的链接。这些链接存在于响应消息中的专门部分,它的重点是告诉我们下一步可以做什么,以及我们需要操作的资源的URI。
这么做的优点包括无需在客户端中硬编码大量的URL,起到松耦合的作用。
(正如前面在描述"统一接口"时那样,我认为HATEOAS的缺点也比较明显,存在安全性和无法丰富描述接口的缺点。可能是因为这样,HATEOAS并没有流行起来,准确地说是我没有看到哪个系统在用HATEOAS)
这是Richardson Maturity Model的最后一级。
将版本号用于RESTful API
假设你设计了一个网站,前端和后端都是你写的,如果某个后端API调整了,因为前端也是部署在你的服务器上,所以你可以很方便的对前端对应的这个API调用文本进行更换。
但这么做仅限于一个单纯的网站系统。如果客户端并非只有网页,还包括用户下载的桌面应用、或你的API作为第三方API提供给其它人使用。那么你无权修改这些客户端编码的API。你需要对原有的API返回一些警告,并为想要进行的调整用一个新的API提供。
随着技术和环境的发展,API必然不能在出生时就完全确定下来,一直不变,否则它们会很难进化。将版本号应用于API,就成了一个必要性的需求。
RESTful API 中使用版本号,主要有两种形式:一种是把版本号放置在URL中,一种是把版本号放置在HTTP Header中。(参考RESTful API进行版本控制)
把版本号放置于URL,无论对API提供方还是调用方来说,都是最直观、简洁、简单的一种。
将版本号放置于URL,在一定程度上会干扰对"用URL标识资源"的遵守和理解。但它确实是最简单有效的方式。
注意:版本号应当尽量地被用来 保障 对操作资源的参数的演变。在API设计之初,应当努力将信息抽象为资源,使其符合RESTful,而不是日后让版本号来承担API设计风格上的错误。版本号不是对API设计上的放纵,不应该因为有版本号而在一开始就随意地设计API
应用实例- 微信支付接口
-
微信支付接口的老版本(v2),这时候还不是 RESTful API
-
最新的v3版本,已经采取了RESTful API。相比旧版更加清晰明了。并可以看到URL采用了版本号标识
v3
应用实例- PayPal支付接口
⭐把书读薄 – 要点总结
① REST的定义:为分布式超媒体系统设计的一个混合式架构风格
② REST和Web的联系:Web是世界上最大的分布式超媒体系统,所以REST适用于Web。并且作者在第六章表示,REST从从设计之初就是为了指导Web架构的设计和开发。
之所以REST在定义上没有指定Web,是因为REST具有通用性。松耦合和通用性是架构师的两个设计原则,Fielding也一样。
③ REST和其它网络架构的区别:REST是一个混合式架构风格。"CS、无状态、缓存"这三个约束是从早期网络架构中借鉴来的。"统一接口、分层系统、按需代码(可选)"是REST特有的,其中"统一接口"是REST区分于其它网络架构的核心特征。统一接口延伸出了RESTful API,所以很多人对REST的理解就是使用RESTful API,对于一个单纯的使用者来说,这无可厚非。
④ REST的核心:面向资源是REST的核心。正如5.2.1.1所说,REST对信息的核心抽象是资源
⑤ Fielding是Web架构的奠基者之一:Fielding即是REST的作者,又是Apache HTTP服务器的主要设计者,还是URI、HTTP的主要设计者。所以Fielding对Web的理解应当是深刻的,REST论文值得所有web开发者重视
⑥ REST和HTTP:目前为止,HTTP依然是实现REST的最佳选择,毕竟HTTP是受REST指导而设计的。不过,HTTP1.1开始才真正符合REST架构思想。这也是HTTP1.1发布后,REST才发表的原因之一吧。(HTTP1.1于1999年发布,REST论文于2000年发表)
理解本真的 REST 架构风格
本文是“深入探索 REST”专栏系列深度内容中的第二篇,它将带您领略 REST 架构的起源、与 Web 的关系、REST 架构的本质及特性,以及 REST 架构与其他架构风格之间的比较。
引子
在移动互联网、云计算迅猛发展的今天,作为一名 Web 开发者,如果您还没听说过“REST”这个 buzzword,显然已经落伍了。夸张点说,甚至“出了门都不好意思跟别人打招呼”。尽管如此,对于 REST 这个泊来品的理解,大多数人(包括一些资深的架构师)仍然停留在“盲人摸象”的阶段。常常听到各种各样关于 REST 的说法,例如:有人说:“我们这套新的 API 决定不用 Web Service(SOAP+WSDL),而是直接使用 HTTP+JSON,也就是用 RESTful 的方式来开发。” 不用 SOAP,甚至也不用 XML,就自动变成了 RESTful 了。还有人认为:REST 与传统的 Web Service 其实没有本质区别,只是对于 URI 的构造方式提出了更多要求,而这些要求 Web Service 完全都可以实现。潜台词是:既生瑜,何生亮。Web Service 已经足够好了,干嘛还要再折腾什么 REST。这些对于 REST 的不同说法,果真如此吗?REST 究竟是什么?是一种新的技术、一种新的架构、还是一种新的规范?
对于这些问题笔者先不解答,为了深入理解 REST 是什么,我们需要回顾一下 Web 发展的最初年代,从源头上讲讲 REST 是怎么得来的。
Web 技术发展与 REST 的由来
Web(万维网 World Wide Web 的简称)是个包罗万象的万花筒,不同的人从不同的角度观察,对于 Web 究竟是什么会得出大不相同的观点。作为 Web 开发者,我们需要从技术上来理解 Web。从技术架构层面上看,Web 的技术架构包括了四个基石:
- URI
- HTTP
- HyperText(除了 HTML 外,也可以是带有超链接的 XML 或 JSON)
- MIME
这四个基石相互支撑,促使 Web 这座宏伟的大厦以几何级数的速度发展了起来。在这四个基石之上,Web 开发技术的发展可以粗略划分成以下几个阶段:
- 静态内容阶段:在这个最初的阶段,使用 Web 的主要是一些研究机构。Web 由大量的静态 HTML 文档组成,其中大多是一些学术论文。Web 服务器可以被看作是支持超文本的共享文件服务器。
- CGI 程序阶段:在这个阶段,Web 服务器增加了一些编程 API。通过这些 API 编写的应用程序,可以向客户端提供一些动态变化的内容。Web 服务器与应用程序之间的通信,通过 CGI(Common Gateway Interface)协议完成,应用程序被称作 CGI 程序。
- 脚本语言阶段:在这个阶段,服务器端出现了 ASP、PHP、JSP、ColdFusion 等支持 session 的脚本语言技术,浏览器端出现了 Java Applet、JavaScript 等技术。使用这些技术,可以提供更加丰富的动态内容。
- 瘦客户端应用阶段:在这个阶段,在服务器端出现了独立于 Web 服务器的应用服务器。同时出现了 Web MVC 开发模式,各种 Web MVC 开发框架逐渐流行,并且占据了统治地位。基于这些框架开发的 Web 应用,通常都是瘦客户端应用,因为它们是在服务器端生成全部的动态内容。
- RIA 应用阶段:在这个阶段,出现了多种 RIA(Rich Internet Application)技术,大幅改善了 Web 应用的用户体验。应用最为广泛的 RIA 技术是 DHTML+Ajax。Ajax 技术支持在不刷新页面的情况下动态更新页面中的局部内容。同时诞生了大量的 Web 前端 DHTML 开发库,例如 Prototype、Dojo、ExtJS、jQuery/jQuery UI 等等,很多开发库都支持单页面应用(Single Page Application)的开发。其他的 RIA 技术还有 Adobe 公司的 Flex、微软公司的 Silverlight、Sun 公司的 JavaFX(现在为 Oracle 公司所有)等等。
- 移动 Web 应用阶段:在这个阶段,出现了大量面向移动设备的 Web 应用开发技术。除了 Android、iOS、Windows Phone 等操作系统平台原生的开发技术之外,基于 HTML5 的开发技术也变得非常流行。
从上述 Web 开发技术的发展过程看,Web 从最初其设计者所构思的主要支持静态文档的阶段,逐渐变得越来越动态化。Web 应用的交互模式,变得越来越复杂:从静态文档发展到以内容为主的门户网站、电子商务网站、搜索引擎、社交网站,再到以娱乐为主的大型多人在线游戏、手机游戏。
在互联网行业,实践总是走在理论的前面。Web 发展到了 1995 年,在 CGI、ASP 等技术出现之后,沿用了多年、主要面向静态文档的 HTTP/1.0 协议已经无法满足 Web 应用的开发需求,因此需要设计新版本的 HTTP 协议。在 HTTP/1.0 协议专家组之中,有一位年轻人脱颖而出,显示出了不凡的洞察力,后来他成为了 HTTP/1.1 协议专家组的负责人。这位年轻人就是 Apache HTTP 服务器的核心开发者 Roy Fielding,他还是 Apache 软件基金会的合作创始人。
Roy Fielding 和他的同事们在 HTTP/1.1 协议的设计工作中,对于 Web 之所以取得巨大成功,在技术架构方面的因素做了一番深入的总结。Fielding 将这些总结纳入到了一套理论框架之中,然后使用这套理论框架中的指导原则,来指导 HTTP/1.1 协议的设计方向。HTTP/1.1 协议的第一个草稿是在 1996 年 1 月发布的,经过了三年多时间的修订,于 1999 年 6 月成为了 IETF 的正式规范(包括了 RFC 2616 以及用于对客户端做身份认证的 RFC 2617)。HTTP/1.1 协议设计的极为成功,以至于发布之后整整 10 年时间里,都没有多少人认为有修订的必要。用来指导 HTTP/1.1 协议设计的这套理论框架,最初是以备忘录的形式在专家组成员之间交流,除了 IETF/W3C 的专家圈子,并没有在外界广泛流传。Fielding 在完成 HTTP/1.1 协议的设计工作之后,回到了加州大学欧文分校继续攻读自己的博士学位。第二年(2000 年)在他的博士学位论文 Architectural Styles and the Design of Network-based Software Architectures 中,Fielding 更为系统、严谨地阐述了这套理论框架,并且使用这套理论框架推导出了一种新的架构风格,并且为这种架构风格取了一个令人轻松愉快的名字“REST”——Representational State Transfer(表述性状态转移)的缩写。
在笔者看来,Fielding 这篇博士论文在 Web 发展史上的价值,不亚于 Web 之父 Tim Berners-Lee 关于超文本的那篇经典论文。然而遗憾的是,这篇博士论文在诞生之后的将近 5 年时间里,一直没有得到足够的重视。例如 Web Service 相关规范 SOAP/WSDL 的设计者们,显然不大理解 REST 是什么,HTTP/1.1 究竟是一个什么样的协议、为何要设计成这个样子。
这种情况在 2005 年之后有了很大的改善,随着 Ajax、Ruby on Rails 等新的 Web 开发技术的兴起,在 Web 开发技术社区掀起了一场重归 Web 架构设计本源的运动,REST 架构风格得到了越来越多的关注。在 2007 年 1 月,支持 REST 开发的 Ruby on Rails 1.2 版正式发布,并且将支持 REST 开发作为 Rails 未来发展中的优先内容。Ruby on Rails 的创始人 DHH 做了一个名为“World of Resources”的精彩演讲,DHH 在 Web 开发技术社区中的强大影响力,使得 REST 一下子处在 Web 开发技术舞台的聚光灯之下。
今天,各种流行的 Web 开发框架,几乎没有不支持 REST 开发的了。大多数 Web 开发者都是通过阅读某种 REST 开发框架的文档,以及通过一些例子代码来学习 REST 开发的。然而,通过例子代码来学习 REST 有非常大的局限性。因为 REST 并不是一种具体的技术,也不是一种具体的规范,REST 其实是一种内涵非常丰富的架构风格。通过例子代码来学习 REST,除了学习到一种有趣的 Web 开发技术之外,并不能全面深入的理解 REST 究竟是什么。甚至还会误以为这些简单的例子代码就是 REST 本身,REST 不过是一种简单的 Web 开发技术而已。就像盲人摸象一样,有的人摸到了象鼻子、有的人摸到了象耳朵、有的人摸到了象腿、有的人摸到了象尾巴。他们都坚信自己感觉到的大象,才是最真实的大象,而其他人的感觉都是错误的。
对于不理解 REST 的 Web 开发者,人们习惯于展示一些例子代码来让他们理解 REST,笔者不赞同上述做法。如果 Web 开发者想要深入理解 REST 是什么,就很难避开 Fielding 的这篇博士论文。笔者在本文中对于 REST 是什么的介绍,也是基于 Fielding 的博士论文的。尽管如此,笔者强烈建议本文的读者亲自去通读一下 Fielding 的博士论文,就像想要了解孔子的思想应该直接去读《论语》等著作,而不是首先去读其他人的转述一样。笔者在本文中也仅仅是努力不做一个把经书念错了的歪嘴和尚而已。那么,下面我们言归正传。
在 Fielding 的这篇名为 Architectural Styles and the Design of Network-based Software Architectures 的博士论文(中文版名为《架构风格与基于网络的软件架构设计》)中,提出了一整套基于网络的软件(即所谓的“分布式应用”)的设计方法,值得所有分布式应用的开发者仔细阅读、深入体会。
在论文的前三章中,Fielding 在批判性继承前人研究成果的基础上,建立起来一整套研究和评价软件架构的方法论。这套方法论的核心是“架构风格”这个概念。架构风格是一种研究和评价软件架构设计的方法,它是比架构更加抽象的概念。一种架构风格是由一组相互协作的架构约束来定义的。架构约束是指软件的运行环境施加在架构设计之上的约束。
在论文的第四章中,Fielding 研究了 Web 这样一个分布式系统对于软件架构设计提出了哪些需求。在第五章中,Fielding 将第四章 Web 提出的需求具体化为一些架构约束,通过逐步添加各种架构约束,推导出来了 REST 这种新的架构风格。
REST 架构风格的推导过程如下图所示:
图 1:REST 所继承的架构风格约束(原图可在这里下载)
在图 1 中,每一个椭圆形里面的缩写词代表了一种架构风格,而每一个箭头边的单词代表了一种架构约束。
REST 架构风格最重要的架构约束有 6 个:
- 客户 - 服务器(Client-Server)
通信只能由客户端单方面发起,表现为请求 - 响应的形式。
- 无状态(Stateless)
通信的会话状态(Session State)应该全部由客户端负责维护。
- 缓存(Cache)
响应内容可以在通信链的某处被缓存,以改善网络效率。
- 统一接口(Uniform Interface)
通信链的组件之间通过统一的接口相互通信,以提高交互的可见性。
- 分层系统(Layered System)
通过限制组件的行为(即,每个组件只能“看到”与其交互的紧邻层),将架构分解为若干等级的层。
- 按需代码(Code-On-Demand,可选)
支持通过下载并执行一些代码(例如 Java Applet、Flash 或 JavaScript),对客户端的功能进行扩展。
在论文中推导出的 REST 架构风格如下图所示:
图 2:REST 架构风格(原图可在这里下载)
而 HTTP/1.1 协议作为一种 REST 架构风格的架构实例,其架构如下图所示:
图 3:一个基于 REST 的架构的过程视图(原图可在这里下载)
用户代理处在三个并行交互(a、b 和 c)的中间。用户代理的客户端连接器缓存无法满足请求,因此它根据每个资源标识符的属性和客户端连接器的配置,将每个请求路由到资源的来源。请求(a)被发送到一个本地代理,代理随后访问一个通过 DNS 查找发现的缓存网关,该网关将这个请求转发到一个能够满足该请求的来源服务器,服务器的内部资源由一个封装过的对象请求代理(object request broker)架构来定义。请求(b)直接发送到一个来源服务器,它能够通过自己的缓存来满足这个请求。请求(c)被发送到一个代理,它能够直接访问 WAIS(一种与 Web 架构分离的信息服务),并将 WAIS 的响应翻译为一种通用的连接器接口能够识别的格式。每一个组件只知道与它们自己的客户端或服务器连接器的交互;整个过程拓扑是我们的视图的产物。
通过比较图 2 和图 3,读者不难发现这两张图中的架构是高度一致的。对于 HTTP/1.1 协议为何要设计成这个样子,读者想必已经有所领悟。
在论文的第六章中,Fielding 对于到 2000 年为止在 Web 基础架构协议的设计和开发方面的一些经验教训进行了深入的分析。其中,“HTTP 不是 RPC”、“HTTP 不是一种传输协议”两部分值得读者反复阅读。时至 13 年之后的今日,对于 HTTP 协议的误解仍然广泛存在。
以上简要介绍了 Fielding 博士论文中的内容。为了帮助读者仔细阅读 Fielding 的博士论文,笔者整理了一套 Fielding 博士论文的导读,将在本专栏后续文章中载出。
REST 详解
REST 究竟是什么?因为 REST 的内涵非常丰富,所以很难用一两句话解释清楚这个问题。
首先,REST 是 Web 自身的架构风格。REST 也是 Web 之所以取得成功的技术架构方面因素的总结。REST 是世界上最成功的分布式应用架构风格(成功案例:Web,还不够吗?)。它是为 运行在互联网环境 的 分布式 超媒体系统量身定制的。互联网环境与企业内网环境有非常大的差别,最主要的差别是两个方面:
-
可伸缩性需求无法控制:并发访问量可能会暴涨,也可能会暴跌。
-
安全性需求无法控制:无法控制客户端发来的请求的格式,很可能会是恶意的请求。
而所谓的“超媒体系统”,即,使用了超文本的系统。可以把“超媒体”理解为超文本 + 媒体内容。
REST 是 HTTP/1.1 协议等 Web 规范的设计指导原则,HTTP/1.1 协议正是为实现 REST 风格的架构而设计的。新的 Web 规范,其设计必须符合 REST 的要求,否则整个 Web 的体系架构会因为引入严重矛盾而崩溃。这句话不是危言耸听,做个类比,假如苏州市政府同意在市区著名园林的附近大型土木,建造大量具有后现代风格的摩天大楼,那么不久之后世界闻名的苏州园林美景将不复存在。
上述这些关于“REST 是什么”的描述,可以总结为一句话:REST 是所有 Web 应用都应该遵守的架构设计指导原则。当然,REST 并不是法律,违反了 REST 的指导原则,仍然能够实现应用的功能。但是违反了 REST 的指导原则,会付出很多代价,特别是对于大流量的网站而言。
要深入理解 REST,需要理解 REST 的五个关键词:
- 资源(Resource)
- 资源的表述(Representation)
- 状态转移(State Transfer)
- 统一接口(Uniform Interface)
- 超文本驱动(Hypertext Driven)
什么是资源?
资源是一种看待服务器的方式,即,将服务器看作是由很多离散的资源组成。每个资源是服务器上一个可命名的抽象概念。因为资源是一个抽象的概念,所以它不仅仅能代表服务器文件系统中的一个文件、数据库中的一张表等等具体的东西,可以将资源设计的要多抽象有多抽象,只要想象力允许而且客户端应用开发者能够理解。与面向对象设计类似,资源是以名词为核心来组织的,首先关注的是名词。一个资源可以由一个或多个 URI 来标识。URI 既是资源的名称,也是资源在 Web 上的地址。对某个资源感兴趣的客户端应用,可以通过资源的 URI 与其进行交互。
什么是资源的表述?
资源的表述是一段对于资源在某个特定时刻的状态的描述。可以在客户端 - 服务器端之间转移(交换)。资源的表述可以有多种格式,例如 HTML/XML/JSON/ 纯文本 / 图片 / 视频 / 音频等等。资源的表述格式可以通过协商机制来确定。请求 - 响应方向的表述通常使用不同的格式。
什么是状态转移?
状态转移(state transfer)与状态机中的状态迁移(state transition)的含义是不同的。状态转移说的是:在客户端和服务器端之间转移(transfer)代表资源状态的表述。通过转移和操作资源的表述,来间接实现操作资源的目的。
什么是统一接口?
REST 要求,必须通过统一的接口来对资源执行各种操作。对于每个资源只能执行一组有限的操作。以 HTTP/1.1 协议为例,HTTP/1.1 协议定义了一个操作资源的统一接口,主要包括以下内容:
-
7 个 HTTP 方法:GET/POST/PUT/DELETE/PATCH/HEAD/OPTIONS
-
HTTP 头信息(可自定义)
-
HTTP 响应状态代码(可自定义)
-
一套标准的内容协商机制
-
一套标准的缓存机制
-
一套标准的客户端身份认证机制
REST 还要求,对于资源执行的操作,其操作语义必须由 HTTP 消息体之前的部分完全表达,不能将操作语义封装在 HTTP 消息体内部。这样做是为了提高交互的可见性,以便于通信链的中间组件实现缓存、安全审计等等功能。
什么是超文本驱动?
“超文本驱动”又名“将超媒体作为应用状态的引擎”(Hypermedia As The Engine Of Application State,来自 Fielding 博士论文中的一句话,缩写为 HATEOAS)。将 Web 应用看作是一个由很多状态(应用状态)组成的有限状态机。资源之间通过超链接相互关联,超链接既代表资源之间的关系,也代表可执行的状态迁移。在超媒体之中不仅仅包含数据,还包含了状态迁移的语义。以超媒体作为引擎,驱动 Web 应用的状态迁移。通过超媒体暴露出服务器所提供的资源,服务器提供了哪些资源是在运行时通过解析超媒体发现的,而不是事先定义的。从面向服务的角度看,超媒体定义了服务器所提供服务的协议。客户端应该依赖的是超媒体的状态迁移语义,而不应该对于是否存在某个 URI 或 URI 的某种特殊构造方式作出假设。一切都有可能变化,只有超媒体的状态迁移语义能够长期保持稳定。
一旦读者理解了上述 REST 的五个关键词,就很容易理解 REST 风格的架构所具有的 6 个的主要特征:
-
面向资源(Resource Oriented)
-
可寻址(Addressability)
-
连通性(Connectedness)
-
无状态(Statelessness)
-
统一接口(Uniform Interface)
-
超文本驱动(Hypertext Driven)
这 6 个特征是 REST 架构设计优秀程度的判断标准。其中,面向资源是 REST 最明显的特征,即,REST 架构设计是以资源抽象为核心展开的。可寻址说的是:每一个资源在 Web 之上都有自己的地址。连通性说的是:应该尽量避免设计孤立的资源,除了设计资源本身,还需要设计资源之间的关联关系,并且通过超链接将资源关联起来。无状态、统一接口是 REST 的两种架构约束,超文本驱动是 REST 的一个关键词,在前面都已经解释过,就不再赘述了。
从架构风格的抽象高度来看,常见的分布式应用架构风格有三种:
- 分布式对象(Distributed Objects,简称 DO)
架构实例有 CORBA/RMI/EJB/DCOM/.NET Remoting 等等
- 远程过程调用(Remote Procedure Call,简称 RPC)
架构实例有 SOAP/XML-RPC/Hessian/Flash AMF/DWR 等等
- 表述性状态转移(Representational State Transfer,简称 REST)
架构实例有 HTTP/WebDAV
DO 和 RPC 这两种架构风格在企业应用中非常普遍,而 REST 则是 Web 应用的架构风格,它们之间有非常大的差别。
REST 与 DO 的差别在于:
-
REST 支持抽象(即建模)的工具是资源,DO 支持抽象的工具是对象。在不同的编程语言中,对象的定义有很大差别,所以 DO 风格的架构通常都是与某种编程语言绑定的。跨语言交互即使能实现,实现起来也会非常复杂。而 REST 中的资源,则完全中立于开发平台和编程语言,可以使用任何编程语言来实现。
-
DO 中没有统一接口的概念。不同的 API,接口设计风格可以完全不同。DO 也不支持操作语义对于中间组件的可见性。
-
DO 中没有使用超文本,响应的内容中只包含对象本身。REST 使用了超文本,可以实现更大粒度的交互,交互的效率比 DO 更高。
-
REST 支持数据流和管道,DO 不支持数据流和管道。
-
DO 风格通常会带来客户端与服务器端的紧耦合。在三种架构风格之中,DO 风格的耦合度是最大的,而 REST 的风格耦合度是最小的。REST 松耦合的源泉来自于统一接口 + 超文本驱动。
REST 与 RPC 的差别在于:
-
REST 支持抽象的工具是资源,RPC 支持抽象的工具是过程。REST 风格的架构建模是以名词为核心的,RPC 风格的架构建模是以动词为核心的。简单类比一下,REST 是面向对象编程,RPC 则是面向过程编程。
-
RPC 中没有统一接口的概念。不同的 API,接口设计风格可以完全不同。RPC 也不支持操作语义对于中间组件的可见性。
-
RPC 中没有使用超文本,响应的内容中只包含消息本身。REST 使用了超文本,可以实现更大粒度的交互,交互的效率比 RPC 更高。
-
REST 支持数据流和管道,RPC 不支持数据流和管道。
-
因为使用了平台中立的消息,RPC 风格的耦合度比 DO 风格要小一些,但是 RPC 风格也常常会带来客户端与服务器端的紧耦合。支持统一接口 + 超文本驱动的 REST 风格,可以达到最小的耦合度。
比较了三种架构风格之间的差别之后,从面向实用的角度来看,REST 架构风格可以为 Web 开发者带来三方面的利益:
- 简单性
采用 REST 架构风格,对于开发、测试、运维人员来说,都会更简单。可以充分利用大量 HTTP 服务器端和客户端开发库、Web 功能测试 / 性能测试工具、HTTP 缓存、HTTP 代理服务器、防火墙。这些开发库和基础设施早已成为了日常用品,不需要什么火箭科技(例如神奇昂贵的应用服务器、中间件)就能解决大多数可伸缩性方面的问题。
- 可伸缩性
充分利用好通信链各个位置的 HTTP 缓存组件,可以带来更好的可伸缩性。其实很多时候,在 Web 前端做性能优化,产生的效果不亚于仅仅在服务器端做性能优化,但是 HTTP 协议层面的缓存常常被一些资深的架构师完全忽略掉。
- 松耦合
统一接口 + 超文本驱动,带来了最大限度的松耦合。允许服务器端和客户端程序在很大范围内,相对独立地进化。对于设计面向企业内网的 API 来说,松耦合并不是一个很重要的设计关注点。但是对于设计面向互联网的 API 来说,松耦合变成了一个必选项,不仅在设计时应该关注,而且应该放在最优先位置。
有的读者可能会问:“你说了这么多,REST 难道就没有任何缺点了吗?”当然不是,正如 Fielding 在博士论文中阐述的那样,评价一种软件架构的优劣,不能脱离开软件的具体运行环境。永远不存在适用于任何运行环境的、包治百病的银弹式架构。笔者在前面强调过 REST 是一种为运行在互联网环境中的 Web 应用量身定制的架构风格。REST 在互联网这个运行环境之中已经占据了统治地位,然而,在企业内网运行环境之中,REST 还会面临 DO、RPC 的巨大挑战。特别是一些对实时性要求很高的应用,REST 的表现不如 DO 和 RPC。所以需要针对具体的运行环境来具体问题具体分析。但是,REST 可以带来的上述三方面的利益即使在开发企业应用时,仍然是非常有价值的。所以 REST 在企业应用开发,特别是在 SOA 架构的开发中,已经得到了越来越大的重视。本专栏将有一篇文章专门介绍 REST 在企业级应用中与 SOA 的结合。
到了这里,“REST 究竟是什么”这个问题笔者就解答完了。本文开头那些说法是否正确,笔者还是笑而不语,读者此时应该已经有了自己的判断。在接下来的 REST 系列文章中,我将会为读者澄清一些关于 HTTP 协议和 REST 的常见误解。
参考资料:
感谢马国耀对本文的策划和审校。
以上是关于REST系列详解REST架构风格 —— 带你阅读Web发展史上的一个重要技术文献的主要内容,如果未能解决你的问题,请参考以下文章
SpringMVC入门系列篇3:@RequestMapping & @RequestHeader & @CookieValue详解与REST风格请求