REST - 表述性状态转移

表述性状态转移(REST - Representional State Transfer)

The Representational State Transfer (REST) style is an abstraction of the architectural elements within a distributed hypermedia system. - Roy T.Fielding 2000 (Architectural Styles and the Design of Network-based Software Architectures)

引言

在当今的互联网,有三种技术为其提供支撑。

  • URL (Uniform Resource Locator) 命名约定
  • HTTP (HyperText Transfer Protocol) 协议
  • HTML (Hypertext Markup Language) 文档格式

一、资源

用URL命名的事物的专业术语是资源(Resource)。

万物皆可为资源。

就其本质而言,任何足够重要并被引用的事物都可以是资源。在《万维网的架构(第一卷)》(The Architecture of the World Wide Web, Volume One)(实际上没有第二卷)中如此描述“想要建立指向它的超文本链接,提出或反对它的断言,获取或者缓存它的表述,供另外的表述引用它的全部或部分,给它增加注释信息,或者对它执行某些操作”。

资源可以是保存在电脑中的事物,可以是一个文件、数据库中的一条记录,或者是代码执行的结果。资源也可以是现实中的事物,比如一个水果、一个人、一种颜色,或者其他出现在你身边的物品。

可寻址性

一个事物成为资源的唯一条件是每一个资源必须拥有URL。在Web上,我们使用URL来为每个资源提供一个全球唯一的地址。将一个事物赋予URL,它就会成为一个资源。

  1. 每个URL代表一个也仅代表一个资源。如果有两个从概念上来说并不相同的事物,那么我们应该讲它们作为两个资源并为它们分配不同的URL。

  2. 可寻址性原则就是说每个资源应该有一个属于自己的URL。例如,一个网页就是一个资源,每个网页都有自己的URL,不可能一个URL指向两个不同的网页。URL就是资源的身份证,独一无二的。这样你可以非常清楚地、毫无歧义地引用它。

连通性(Connectedness)

资源之间可以相互连通,从一个资源可以根据URL连接到另外一个资源。

例如,我可以通过点击网页上的链接转到另外一个网页上去。例如,在体检时,一个项目结束后,医生会在体检单上写出下一个项目在哪个房间做,你可以根据房间号(URL)找到它,进行下一项体检。

连通性原则:每个资源都会告诉你如何获取相邻的资源

二、状态

状态是人或事物表现出来的形态。是指现实(或虚拟)事物处于生成、生存、发展、消亡时期或各转化临界点时的形态或事物态势。(百度百科)

应用状态(Application State)

应用状态是一个很抽象的概念,可以从字面上理解为:应用状态就是用户使用的应用所处的状态。

举个例子,某天我想访问去搜索网站查资料。

  • 首先,我打开浏览器,这时应用状态是浏览器设定的打开页面。
  • 然后,我输入搜索网站的URL,进入网站的首页,这是应用状态是搜索网站的首页。
  • 而后,我输入搜索关键字,开始搜索,这时应用状态是搜索结果页面。

在这个例子中,应用状态就是你看到的信息(比如,你停留在哪个页面)。

资源状态(Resource State)

资源的状态就是资源状态。这好像就是一句废话,但是我们对状态的关注往往大于对内容的关注,程序员尤其如此。

比如,一个盒子(资源),如果它是打开的,它的状态(资源状态)是打开的;如果它是关闭的,它的状态就是关闭的。

三、表述

表述是一种以机器可读的方式对资源当前状态的说明。

表述描述资源状态

一个石榴可以是一个资源,但是你不可能通过网络将石榴进行传输;数据库的一条记录可以是一个资源,你可以通过网络将它一个字节一个字节地发送出去,但是客户端如何处理这堆来源不明并且没有上下文信息的二进制数据呢?

当我们对一个资源发起请求的时候,服务器会以一种有效的方式提供一个包含了资源信息的文档作为回应。例如,对于数据库的一条记录,服务器可以用 XML文档、JSON对象、CSV 数值或者生产它的INSERT语句来描述它。

这就是表述,表述可以是任何机器可读的包含资源相关信息的文档。

资源有多重表述

就像一个人在不同场景下有不同的称呼一样(小名、笔名、网名等),一个资源可以有很多种表述。如上一节讲到的,数据库的一条记录可以用多种方式来表述;一份文档可以能有多种格式,docx或者pdf都表示的同一资源。

客户端如何制定它想要的表述呢?我们有两种策略:

  • 内容协商(Content Negotiation),客户端通过一个HTTP报头的值来区分表述。
  • 分配多个URL,一个URL对应一个表述。

四、HTTP

The Hypertext Transfer Protocol (HTTP) is an application-level protocol for distributed, collaborative, hypermedia information systems. It is a generic, stateless, protocol which can be used for many tasks beyond its use for hypertext, such as name servers and distributed object management systems, through extension of its request methods, error codes and headers. (RFC-2616 Hypertext Transfer Protocol – HTTP/1.1)

短会话(Short Session)

HTTP会话只维持在一次请求过程中,客户端发送请求,服务器进行响应。

这意味着,我可以把电脑关机,第二天打开电脑,当浏览器从内部缓存中恢复昨天访问的网页以后,我依然可以点击页面上的任何一个链接,网页应该可以继续工作的。

这项原则也被称为无状态(stateless)。这个术语是指服务器不必关心客户端的状态(应用状态)。

标准方法

尽管任何事物都可以成为资源,但是客户端不能随心所欲地对资源进行任意的操作。所能进行的操作是有规定的。我们通常使用的规定就是HTTP协议。

HTTP方法是客户端告诉服务器它想如何操作一个资源的方法。RFC-2616 定义了HTTP的8种方法,我们的重点是其中的6种:GET、POST、PUT、DELETE、HEADOPTIONS

五、REST

REST不是一种协议,也不是一种文件格式,更不是一种开发模式。它是一系列的设计约束的集合:无状态性、将超媒体作为应用状态的引擎等。(《Restful Web APIs》)

往来穿梭的表述

由于HTTP会话非常短,所以服务器不知道客户端的应用状态的任何信息;客户端也不能直接控制资源状态(所有资源都是保存在服务器中)。然后,它们却正常运行着,它们就是通过 REST-表述性状态转移 工作的。

  • 应用状态保存在客户端,但是服务器端可以通过发送表述来暗示它。这个发送的表述中描述了所有可能的状态转换。
  • 资源状态保存在服务器端,但是客户端可以通过向服务器发送表述来操作它,这个提交的表述描述了客户端所期望的新的状态。

在现实生活中,当人们去饭店吃饭时,饭店并不知道顾客的状态,它提供了一份菜单(表述),上面有他们能提供的所有菜品(状态转换)。顾客在菜单中选择了菜品,递交了一份点菜票(表述),上面写着需要点的菜品(期望的状态)。饭店根据你点的菜品,为你提供饭菜(资源)。

语义的挑战

Web API的目标是在没有人类参与的前提下完成相应的工作。但是我们如何才能让计算机明白我们需要做的事情呢?Web API的最大挑战就是:消除“理解文档的结构”和“理解文档的含义”之间的语义鸿沟(Semantic Gap)。我们将其称为语义挑战(Semantic Challenge)

六、HTTP协议语义

HTTP 1.1标准定义了8种不同类型的消息。

最常见的:

  1. GET
    获取资源的某个表述。

  2. DELETE
    销毁一个资源。

  3. POST
    基于给定的表述信息,在当前资源的下一级创建一个新的资源。

  4. PUT
    用给定的表述信息替换资源的当前状态。

在分析研究API是经常用到的:

  1. HEAD
    获取服务器发送过来的报头信息(不是资源的表述)。这些报头会随表述被服务器一起发送过来。

  2. OPTIONS
    获取这个资源所能响应的HTTP方法列表。

HTTP扩展方法:

  1. PATCH
    根据提供的表述信息修改资源的部分状态。(RFC-5789 中定义)

其他的HTTP标准方法 CONNECTTRACE 只用于HTTP代理,这里不做介绍。其他的HTTP扩展方法 LINKUNLINK还处于草案阶段。

安全性

HTTP方法的安全性,是指该方法的请求不会修改资源状态,多次发送请求对资源的影响和没有发送请求一样。

客户端绝对不要希望发起的安全请求能改变资源的状态。安全的HTTP方法有:GET、HEADOPTIONS

幂等性(Idempotence)

HTTP方法的幂等性,是指该方法多次请求返回的资源状态是一致的。此时资源状态可能已经与请求之前不同了,但是每次返回的资源状态都是相同的。

也就是说,即使方法会改变资源状态,也只会改变一次,以后将不再改变了。客户端可以重复调用并且期望同样的结果。幂等的HTTP方法有:GET、DELETE、PUT、HEAD、OPTIONS、LINKUNLINK

GET DELETE POST PUT PATCH HEAD OPTIONS
安全性 Yes No No No No Yes Yes
幂等性 Yes Yes No Yes ? Yes Yes

POST-to-Append 与 Overloaded POST

POST是常用的HTTP方法,POST方法有两项工作:

  • POST-to-append
  • overloaded POST

    1. POST-to-Append,向某个资源发送一条POST请求用以在资源的下一级中创建一个新的资源。它会在请求的实体消息体中添加希望创建的资源的表述信息并发送给服务器。

    2. overload的 POST,我们在用浏览器上网时,HTTP POST也被用于传输任何形式的变化。这时它更像一个将PUT、DELETE、PATCH、LINK和UNLINK所有方法混合而成的一个方法。
      此时的POST并不是真正表示“创建一个新的资源”,而是表示“任意而为(whatever)”。

我建议在Web Api中一点也不要使用重载的POST

七、自描述的消息、HTML 和 Content-Type

In computer programming, self-documenting (or self-describing) source code and user interface follow naming conventions and structured programming conventions that enable use of the system without prior specific knowledge. (Wikipedia)

自描述性

所谓自描述性,是指文档中使用了约定的标记来注释需要描述的信息,接收到此文档的人不需要额外学习更多的知识,仅仅根据之前的约定就能明白文档表达的意思。

在上述定义中,有一个关键词需要注意:约定。自描述性是建立在约定的基础之上,交换文档的双方对文档中的标记事先有约定,双方都按照约定来编写和解读文档,约定的标记表达了文字描述中没有表达的题外之意。

约定可以是私有的协议,也可以是所有人公认的标准协议。在互联网中,最有名的的约定就是HTML (Hypertext Markup Language)。

HTML

超级文本标记语言(HTML)是标准通用标记语言下的一个应用,也是一种规范,一种标准,它通过标记符号来标记要显示的网页中的各个部分。

当我们在网页中使用标记时,并不需要写专门的描述来解释标记的含义就能知道它代表了一个链接,可以点击来改变应用状态。

这一切是怎么发生的呢?因为我们都是根据HTML来编写和解读文档,HTML就是我们事前的约定,这个约定帮助人们读懂了文字中没有表达的含义,也帮助计算机(浏览器)解析文档成为了可能。

Content-Type

HTML很成功,成为支撑互联网的三大技术之一。 但HTML中依然有大量为人类操作服务的内容,对于实现Web Api的目标而言,这些内容是冗余的。因此,陆陆续续地涌现出许多自描述语言,例如:XMLJSON等等。

这么多不同约定的文档在同一网络中传输,客户端如何才能知道自己接收到的是什么约定的文档呢?这个就是设计Content-Type报头初衷。

The Content-Type entity header is used to indicate the media type of the resource. In response, a content-type header tells the client what the content type of the returned content actually is.

常用的Content-Type

  • text/html
  • application/xml
  • application/json
  • application/octet-stream

八、后记

URL、HTTP和HTML的出现,推动目前互联网的繁荣。但是Web Api的发展却举步维艰,其中的一个重要的原因是之前提到过的“语义挑战”。

你也许认为有了自描述的消息,有了Content-Type,语义挑战已经不是问题了。你如果这样想,其实是忽略了一个关键的问题,客户端收到的消息到底是说的什么内容。

Web API的目标是在没有人类参与的前提下完成相应的工作。

以HTML为例,HTML文档中虽然使用表示了可能的状态转移,但是却没有解决应该选择哪一个点击的问题,这个问题其实是靠一个昂贵而缓慢的“模块”来解决的,这个模块是人类的大脑。

为了解决语义挑战的问题,人们付出了巨大而艰辛的努力。 例如 hMaze/xml、JSON-Collection、Atom等等。
这些协议在某种程度上解决了特定领域的语义问题,但我们距离目标还是很遥远,还需要我们继续努力。

你可能感兴趣的:(REST)