REST 以及 RESTful 辨析
从REST
概念提出到现在已经20年了,业界的主流实践采纳借鉴了其部分原则,但与其最核心的架构设计渐行渐远。
实际上那个去中心化的、面向全世界开放的万维网时代正在落幕,构建在其基础之上的REST
架构思想,也无可避免地被冷落或者被误解。
定义
REST
全称是Representational State Transfer
。翻译过来是表述性状态转移。字面意思很晦涩。
REST
是web服务的一种软件架构风格。
Roy Thomas Fielding
博士于2000年在他的论文中提出的概念。他将REST
定位为"分布式超媒体应用(Distributed Hypermedia System)"的架构风格。符合REST
风格的架构都可以称作是RESTful
的。
在当时,主流的web服务架构是SOAP
和XML-RPC
。
想要理解REST
就要深入理解其涉及到的几个核心概念以及原则(或者叫约束)。
核心概念:
Resource
资源,是对信息的关键性抽象,任何可以命名的信息都可以定义为资源。通过URI标识,实际使用中通过URL获取。
Representational
资源的表述,比如HTML
,JSON
,XML
,JPEG
等等。HTTP协议中定义了媒体类型,比如text/html
, image/jpeg
、application/json
、text/xml
等。
State Transfer
状态转移,这里指应用的状态转移,不是资源的状态。
用户在操作页面的时候,从他的角度看,他改变了应用程序的状态。使用表述的超媒体(HTML就是一种超媒体)来表示和管理应用程序状态的方式,称为:以超媒体作为应用程序状态引擎( hypermedia as the engine of application state
)或者简称为超文本约束( hypertet constraint
)。
REST架构风格架构约束
REST架构风格最重要的架构约束有6个:
1. Client-server architecture
C/S架构,该原则的主要目的是将服务端和客户端的关注点分离。
2. Stateless
无状态,服务端不保存客户端的上下文信息。每一次客户端发起请求,都要包含必须的所有状态信息。
3. Cacheability
缓存。如同万维网一样, 客户端和中间通讯传递者可以将响应缓存起来。
4. Layered System
分层系统。客户端通常无法确定它是直接连接到最终服务器还是中间连接。在客户端和服务器之间放置代理或负载平衡器,则不会影响它们之间的通信,也不需要更新客户端或服务器代码。
5. Code-On-Demand(optional)
按需代码(可选的)。服务器可以通过传输可执行代码来临时扩展或定制客户端的功能:例如,诸如Java applet之类的已编译组件,或诸如JavaScript之类的客户端脚本。
6. Uniform Interface
统一接口。该约束原则是一切RESTful 系统设计的基础,它简化和分离了架构,使每个部分都可以独立发展。此统一接口的四个约束是:
6.1 Resource identification in requests(请求中的资源识别)
在请求中标识各个资源,例如使用RESTful Web服务中的URI。资源本身在概念上与返回给客户端的表示形式是分开的。例如,服务器可以从数据库中以HTML,XML或JSON格式发送数据,这些都不是服务器的内部表示形式。
6.2 Resource manipulation through representations(通过表示来操纵资源)
当客户端持有资源的表示形式(包括附加的任何元数据)时,它具有足够的信息来修改或删除资源的状态。
6.3 Self-descriptive messages(自我描述的消息)
每个消息都包含足够的信息来描述如何处理该消息。例如,可以通过媒体类型指定要调用的解析器。
6.4 Hypermedia as the engine of application state( HATEOAS,超媒体作为应用程序状态引擎)
访问了REST应用程序的初始URI(类似于访问网站首页的人类Web用户),REST客户端随后应能够动态使用服务器提供的链接来发现其所需的所有可用资源。随着访问的进行,服务器将以文本作为响应,该文本包括指向当前可用其他资源的超链接。不需要使用有关应用程序的结构或动态的信息对客户端进行硬编码。
其他
遵循以上6个约束原则的架构设计都是RESTful
架构。
我们目前大多数人使用的RESTful API
,都是一种混合了SOA
架构的,或者直接就是以RPC思维定义出来的API风格。也难怪很多人会误以为RESTful API
就是采用JSON
格式、使用HTTP
的GET/POST/PUT/DELETE
方法对应查询/新增/修改/删除来操作数据。
这里存在几个误区,第一点,比较初级的错误,很多API
的url
里面带有动词,比如 /user/modify-avator
,/user/comment/canel
这种定义方式实际上是想使用RPC
,将HTTP
退化成一种传输协议,那就不如直接基于TCP
。
第二点,以为RESTful
就是赋予HTTP
的verb
更为清晰的动作含义。比如POST
是新增数,PUT
就是修改。对照上面的6点原则,完全没有提到对资源修改的动作标准。实际上,REST
从没有提及在任何情况该使用哪种HTTP method
的建议。约束原则只强调接口统一,即便使用POST
来更新数据,而不是像大多数人推荐的使用PUT
,这一点也不违反REST
。使用真正的RESTful API
,除了初始的URI
和一组标准化媒体类型(比如HTML
),不需要其他先验知识。因为所有的应用程序状态的转换,必须是由客户端选择服务器提供的选项来驱动。
第三点,以为使用了HTTP
不同的verb
修改资源,就是在做资源的状态转移。这一点的迷惑性很大,只有理解了HATEOAS
,才会明白REST
中的状态转移是指应用的状态,而且是基于用户点击/操作了不同的超链接,使得应用展现不同的资源,从而进入了不同的状态。跟操作变更具体的资源完全不是同一个概念。