架构风格:你真的懂REST吗?

本文探讨以下几个问题:web

  • 什么是REST
  • REST包含哪些约束
  • 什么是RESTful
  • 纯RESTful API的难点在哪里

若是你去搜索「什么是REST」的话,大部分状况下,你看到的基本都是RESTful!api

这类内容主要说的是:浏览器

  • 资源URL应该怎么写
  • 要用GET来获取资源
  • 要用POST来新建资源
  • 要用PUT来更新资源
  • 要用DELETE来删除资源

而实际上REST并非这些,或者说并不彻底是这些!缓存

什么是REST

REST全称Representational State Transfer,出自Roy Thomas Fielding博士的博士论文《Architectural Styles and
the Design of Network-based Software Architectures》第五章(Fielding博士的这篇论文会在后面单独讨论),通常翻译为「表述性状态转移」。服务器

在论文的第6章第一节提到了为何会取REST这么一个名字:restful

The name 「Representational State Transfer」 is intended to evoke an image of how a well-designed Web application behaves: a network of web pages (a virtual state-machine), where the user progresses through the application by selecting links (state transitions), resulting in the next page (representing the next state of the application) being transferred to the user and rendered for their use.
「表述性状态转移」这个名称是为了唤起人们对于一个良好设计的 Web 应用如何运转的印象:一个由网页组成的网络(一个虚拟状态机),用户经过选择连接在应用中前进(状态迁移),致使下一个页面(应用的下一个状态的表述)被转移给用户,而且呈现给他们,以便他们来使用。网络

在「什么是架构模式和架构风格」一文中,提到过:架构

  • 架构风格是一组架构约束
  • REST是一种架构风格

因此,REST是一组架构约束app

REST约束

REST是一个复合架构风格,即它包含了其它的架构风格!负载均衡

REST约束包括:CS,无状态,分层,缓存,统一接口以及按需代码。其中「统一接口」是REST与其它架构风格的主要区别所在!「统一接口」包括了四个子约束:资源的识别,经过表述操做资源,自描述的消息,超媒体做为应用状态引擎!

《Architectural Styles and
the Design of Network-based Software Architectures》第五章给出了REST的完整推导过程,这里简单列出!

从一个没有约束的架构(NullStyle)开始,不断的添加约束,使此架构进化为须要的架构

Null Style:组件之间没有显著边界的系统,一个没有约束的架构

Client-Server

  • 约束:分离关注点(客户端接口和服务端数据存储)
  • 优点:客户端和服务端能够独立的进化。客户端能够与多个服务端通讯,服务端能够方便的伸缩
  • 劣势:下降了性能

Stateless

  • 约束:通讯必须在本质上是无状态的。从客户到服务器的每一个请求都必须包含理解该请求所必需的全部信息,不能利用任何存储在服务器上的上下文,会话状态所以要所有保存在客户端
  • 优点:改善可见性,监视系统没必要为了肯定一个请求的所有性质而去查看该请求以外的多个请求。改善可靠性,减轻了从局部故障中恢复的任务量。改善可伸缩性,没必要在多个请求之间保存状态,从而容许服务器组件迅速释放资源,并进一步简化其实现,由于服务器没必要跨多个请求管理资源的使用。
  • 劣势:下降网络性能,因为不能将状态数据保存在服务器上的共享上下文中,所以增长了在一系列请求中发送的重复数据(每次交互的开销)。将应用状态放在客户端,下降了服务器对于一致的应用行为的控制

Cache

  • 约束:一个请求的响应中的数据被隐式地或显式地标记为可缓存的或不可缓存的
  • 优点:改善网络性能。若是响应是可缓存的,那么客户端缓存就能够为之后的相同请求重用这个响应的数据。可部分或所有消除一些交互,从而经过减小一系列交互的平均延迟时间,来提升效率、可伸缩性和用户可觉察的性能。
  • 劣势:可能下降可靠性,缓存中陈旧的数据与将请求直接发送到服务器获得的数据可能差异很大。

Uniform InterfaceREST核心特征):

  • 约束:组件之间要有一个统一的接口,包括四个子约束:
    • 资源的识别(identification of resources):每一个资源都有各自的标识符。客户端在请求时须要指定该标识符。客户端所获取的是资源的表述,如HTML,XML 或 JSON 格式等。
    • 经过表述操做资源(manipulation of resources through representations):客户端操做的是资源的表述,而不是资源自己。
    • 自描述的消息(self-descriptive messages):每条消息都包含足够的信息来描述如何处理该消息。
    • 超媒体做为应用状态引擎(HATEOAS)(hypermedia as the engine of application state):客户端经过服务器提供的超媒体内容来了解如何操做表述,经过将对表述的操做提交到服务端,服务端来操做资源,继而改变服务端的状态。
  • 优点:简化总体架构,改善可见性,促进独立的可进化性
  • 劣势:下降了效率。信息都使用标准化的形式来转移,而不能使用特定于应用的需求的形式。

** Layered System**:

  • 约束:经过限制组件的行为,将架构分解为若干等级的层。
  • 优点:经过将组件对系统的知识限制在单一层内,为整个系统的复杂性设置了边界,而且提升了底层独立性。使用层来封装遗留的服务,使新的服务免受遗留客户端的影响;经过将不经常使用的功能转移到一个共享的中间组件中,从而简化组件的实现。中间组件还可以经过支持跨多个网络和处理器的负载均衡,来改善系统的可伸缩性
  • 劣势:增长了数据处理的开销和延迟,所以下降了用户可觉察的性能。能够经过在中间层使用共享缓存来弥补这一缺点。

Code-On-Demand(可选):

  • 约束:一个客户端组件知道如何访问一组资源,但不知道如何处理它们。它向一个远程服务器发送对于如何处理资源的代码的请求,接收这些代码,而后在本地执行这些代码
  • 优点:可以为一个已部署的客户端添加功能,改善了可扩展性和可配置性;当代码可以使它的动做适应于客户端的环境,并在本地与用户交互而不是经过远程交互时,可以获得更好的用户可觉察性能和效率。因为服务器将工做交给了客户端(不然将消耗服务器的资源),从而改善了服务器的可伸缩性
  • 劣势:因为须要管理求值环境,下降了简单性,在一些状况下能够经过简化静态的客户端功能获得补偿。最大的限制是因为服务器发送代码而不是简单的数据,所以缺少可见性。若是客户端没法信任服务器,缺少可见性会致使明显的部署问题。

总结

可能看完了推导,你仍是不知道REST是什么!下面我经过一个列子来解释什么是「REST」!

举个例子

咱们先看看Fielding博士为何要设计REST?Fielding博士在论文里提到了,他设计REST是为了指导现代Web架构的设计与开发!基于REST,Fielding博士设计了HTTP1.1!也就是说,HTTP1.1是符合REST的!因此要搞懂REST,只要理解HTTP1.1就能够了!

若是你作过Web应用,那么CS,分层,无状态,缓存应该都很好理解,这里就不赘述了!按需代码就是相似Flash,Applet这类Web端应用,用以扩展Web功能的!

这里只说一下「统一接口」这个约束!

咱们就以一个简单的HTTP请求来解释REST!

好比你输入www.abc.com时:

  • 你经过标示符来定位到www.abc.com网站的首页,abc站点将首页资源组装成Response信息返回到你的浏览器(资源的识别)
  • 返回的内容头里(HTTP header),告诉了浏览器该如何处理返回的信息(自描述的消息)
  • 返回的信息体(HTTP body),通常是HTML格式,它是你访问的首页资源的表述,里面包含了你能对这个表述进行的操做,好比能访问哪些连接,能提交哪些数据(超媒体做为应用状态引擎)
  • 你点击连接后,这是对表述的操做,你根本没有接触到真实的资源(经过表述操做资源)
  • 服务端接收到你的请求后,将对应连接的资源组装成Response信息返回(此时应用的状态就改变了)。
  • 浏览器接到返回后,将页面渲染出来,你能够进行下一步的操做。

什么是RESTful

上面解释了什么是「REST」!如今来解释一下什么是RESTful!

前面说了,REST是一组架构约束!那么,若是一个应用知足了REST约束,那么咱们就能够称这个应用是RESTful的

虽然,不少系统自称是RESTful的,可是,实际上,绝大部分系统都不是RESTful的,或者不是彻底RESTful的!Fielding博士对这个问题,发表了一篇博文,明确什么系统才能称为是符合我REST的!文中明确说明,系统必须知足HATEOAS约束才能称为是符合REST的!而HATEOAS很难实现!由于有人的参与!

为了缓解这个尴尬,Richardson 提出了「REST成熟度模型」。该模型把 REST 服务按照成熟度划分红 4 个层次:

  • 第一个层次(Level 0)的 Web 服务只是使用 HTTP 做为传输方式,实际上只是远程方法调用(RPC)的一种具体形式。SOAP 和 XML-RPC 都属于此类。
  • 第二个层次(Level 1)的 Web 服务引入了资源的概念。每一个资源有对应的标识符和表述。
  • 第三个层次(Level 2)的 Web 服务使用不一样的 HTTP 方法来进行不一样的操做,而且使用 HTTP 状态码来表示不一样的结果。如 HTTP GET 方法来获取资源,HTTP DELETE 方法来删除资源。
  • 第四个层次(Level 3)的 Web 服务使用 HATEOAS。在资源的表述中包含了连接信息。客户端能够根据连接来发现能够执行的动做。

从上述 REST 成熟度模型中能够看到,使用 HATEOAS 的 REST 服务是成熟度最高的,也是推荐的作法。

  • 对于不使用 HATEOAS 的 REST 服务,客户端和服务器的实现之间是紧密耦合的。客户端须要根据服务器提供的相关文档来了解所暴露的资源和对应的操做。当服务器发生了变化时,如修改了资源的 URI,客户端也须要进行相应的修改。
  • 而使用 HATEOAS 的 REST 服务中,客户端能够经过服务器提供的资源的表达来智能地发现能够执行的操做。当服务器发生了变化时,客户端并不须要作出修改,由于资源的 URI 和其余信息都是动态发现的。

如今大部分的自称是RESTful的系统,通常只能达到第三个层次!

HATEOAS的难点

HATEOAS为何难以实现?是由于客户端没法决策!HTTP能实现RESTful,是由于浏览器只是将表述以及对资源的操做选项展现了出来,至于具体该如何操做,是由使用浏览器的人来决定的!也就是说,虽然服务端告诉了客户端操做的可选项,可是客户端没办法知道该选择什么!
网页浏览是有人的参与的,可是RESTful API是没有人参与的,这就致使RESTful API的客户端难以作出决定,该作什么!

可行的解决办法是:

  • 语义分析:客户端具备语义分析能力,可以自动的分析出后面须要执行哪一个操做,目前这个很难实现
  • 客户端领域设计:客户端引入领域设计,在一个领域内,客户端和服务端达成共识,在特定领域内,目前有哪些操做。不过这个仍是作不到只修改服务端就能够实现系统的进化。服务端进化后,客户端须要作对应的调整才能够完成整个系统的进化。

参考资料

相关文章
相关标签/搜索