Skip to content

zongwu's blog

REST 以及 RESTful 辨析

REST概念提出到现在已经20年了,业界的主流实践采纳借鉴了其部分原则,但与其最核心的架构设计渐行渐远。

实际上那个去中心化的、面向全世界开放的万维网时代正在落幕,构建在其基础之上的REST架构思想,也无可避免地被冷落或者被误解。

定义

REST全称是Representational State Transfer。翻译过来是表述性状态转移。字面意思很晦涩。

REST是web服务的一种软件架构风格。

Roy Thomas Fielding博士于2000年在他的论文中提出的概念。他将REST定位为"分布式超媒体应用(Distributed Hypermedia System)"的架构风格。符合REST风格的架构都可以称作是RESTful的。

在当时,主流的web服务架构是SOAPXML-RPC

想要理解REST就要深入理解其涉及到的几个核心概念以及原则(或者叫约束)。

核心概念:

Resource

资源,是对信息的关键性抽象,任何可以命名的信息都可以定义为资源。通过URI标识,实际使用中通过URL获取。

Representational

资源的表述,比如HTMLJSONXMLJPEG等等。HTTP协议中定义了媒体类型,比如text/htmlimage/jpegapplication/jsontext/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格式、使用HTTPGET/POST/PUT/DELETE方法对应查询/新增/修改/删除来操作数据。

这里存在几个误区,第一点,比较初级的错误,很多APIurl里面带有动词,比如 /user/modify-avator/user/comment/canel 这种定义方式实际上是想使用RPC,将HTTP退化成一种传输协议,那就不如直接基于TCP

第二点,以为RESTful就是赋予HTTPverb更为清晰的动作含义。比如POST是新增数,PUT就是修改。对照上面的6点原则,完全没有提到对资源修改的动作标准。实际上,REST从没有提及在任何情况该使用哪种HTTP method的建议。约束原则只强调接口统一,即便使用POST来更新数据,而不是像大多数人推荐的使用PUT,这一点也不违反REST。使用真正的RESTful API,除了初始的URI和一组标准化媒体类型(比如HTML),不需要其他先验知识。因为所有的应用程序状态的转换,必须是由客户端选择服务器提供的选项来驱动。

第三点,以为使用了HTTP不同的verb修改资源,就是在做资源的状态转移。这一点的迷惑性很大,只有理解了HATEOAS,才会明白REST中的状态转移是指应用的状态,而且是基于用户点击/操作了不同的超链接,使得应用展现不同的资源,从而进入了不同的状态。跟操作变更具体的资源完全不是同一个概念。