REST

REST是Representational state transfer的简称,中文直译过来是『可视化状态转移』或者『具象状态传输』,一眼看上起一头雾水,什么鬼?虽然这个概念很晦涩,但是几乎所有的程序员都用过REST风格的API,比如Github的REST API

GET /users/:username/gists
POST /gists
DELETE /gists/:id/star

一提到REST或者实现一个RESTful API,大家可能都会通过HTTP来实现,以至于很多人把REST等同于HTTP。这个困惑可能很多人都存在,而且REST和HTTP之间也是有着不可割舍的关系,因为这二者的作者(或共同作者)是同一个人:Roy Fielding

Roy Fielding

Representational State Transfer (REST)这个概念是2000年Roy Fielding在他的博士论文《Architectural Styles and the Design of Network-based Software Architectures》中提出的。 他在提出REST架构风格的同时也在进行HTTP/1.1的设计,Roy Fielding在社区中介绍过REST的来历

Throughout the HTTP standardization process, I was called on to defend the design choices of the Web.That is an extremely difficult thing to do within a process that accepts proposals from anyone on a topic that was rapidly becoming the center of an entire industry. I had comments from well over 500 developers, many of whom were distinguished engineers with decades of experience, and I had to explain everything from the most abstract notions of Web interaction to the finest details of HTTP syntax.That process honed my model down to a core set of principles, properties, and constraints that are now called REST.

可以这么说REST是Roy Fielding在设计HTTP/1.1过程中产生的感悟以及对Web的思考,然后他就把它写进了自己的博士论文。Roy Fielding除了是REST和HTTP的主要作者,还是大名鼎鼎的Apache HTTP 服务器的共同创始人。

实际上来说REST不是一个具体的架构,而是一种架构风格:一个设计良好的Web应用应该是一个资源网络,把信息抽象成资源(名词),然后再通过操作(动词)去改变资源的状态,可以类比在数据库中对表进行CRUD操作。HTTP就是REST风格的协议系统。Web应用是基于HTTP的,所以要构建RESTful的Web Service,可以直接使用HTTP已经存在的方法(GET、POST、PUT、DELETE)。

举个例子,比如我们有一个人的信息:id是1024,姓名是foo,年龄是33岁,这个信息存储于服务端,是一个资源,假设这个资源可以用/persons/1024来识别。

可以对这个资源执行的操作包括:

GET /persons/1024 (获取资源)
POST /persons/1024 (更新资源)
PUT /persons/1024 (创建这个资源)
DELETE /persons/1024 (删除资源)

理解了REST的基本理念之后,我们来看看Representational state transfer这个词的具体含义,还是以上面的例子来说明:

  • 首先,这个资源的state是:{name: “foo”,age: 33}(可能以数据库或者缓存等形式存在于服务端)
  • 之后,客户端请求这个资源之后,服务端会把资源的状态以一种表现形式(representation)生成出来,比如JSON、XML、HTML等等
{
    name: "foo",
    age: 33
}

关于对representation,Roy Fielding在论文上是这么定义的:

REST components perform actions on a resource by using a representation to capture the current or intended state of that resource and transferring that representation between components. A representation is a sequence of bytes, plus representation metadata to describe those bytes. Other commonly used but less precise names for a representation include: document, file, and HTTP message entity, instance, or variant.

  • 最后,服务端把这个表现形式传递(transfer)给客户端

这三步完整诠释了Representational state transfer这个词的含义。

最后,让我们来看看RESTful架构的约束,一共有以下6个约束,违反任何一项约束都不能算作是RESTful。

  • Client-Server

client-server约束的原则是把用户端和服务端的关注点进行分离。这样用户端和服务端可以独立演化。

  • 无状态

客户端在进行请求的过程中,服务端不会存储任何客户端信息。每次请求客户端都需要包含所有的信息,包括会话状态,会话状态存储在客户端。会话状态在服务端可以转发给类似于数据库这类的服务,用来在一段时间内保持一个持久的状态,并且可以用来做认证。

  • 可缓存

客户端和任何中间服务都要可以缓存响应内容。响应报文必须指定自身是可缓存的,否则客户端可能会使用过期或者不准确的数据。管理良好的缓存能够部分或者完全消除客户端和服务端之间的交互,进一步提高扩展能力和性能。

  • 系统分层

客户端并不能说清它是直接连接到了最终服务器还是一个中间服务器。中间服务器可以通过负载均衡和分布式缓存来改善系统的扩展能力。并且也可以加强安全策略。

  • Code on demand (optional)

服务端通过传输可执行的代码可以扩展或者定制客户端的行为。可以采用Java applets或者JavaScript等技术。

  • 统一接口 统一接口的约束是设计REST服务的基础。统一接口简化并且解耦了整个架构,这样整个架构的每个部分可以独立进化。统一接口的四个约束分别是:
    • 资源识别

      资源在请求过程中要可以识别,比如在基于web的REST系统中使用URI。资源本身在概念上是和返回给客户端的表示形式(representation)是分离的。比如,服务器可以把数据库中的资源以HTML、XML或者JSON等表现形式发送到客户端,但是这三个都不是资源在服务端内部的形式。

    • 通过资源的表现形式来修改资源

      当一个客户端得到一个资源的表现形式,其中也包含了很多元数据,客户端就有足够的信息可以来修改或者删除资源。

    • 自描述消息

      每个消息都包含足够的信息用来描述如何处理整个消息。比如,可以使用Internet media type(MIME类型)来指定用什么解释器来解析消息。

    • 超媒体作为应用状态的引擎 (Hypermedia as the engine of application state,HATEOAS)

      在访问了一个REST应用的初始URI(就像人类用户访问了一个网站的首页)之后,REST客户端应该可以使用服务端动态提供的链接来发现所有可用的操作和资源。当访问继续,服务端会返回包括超链接的文本,这些超链接指向当前可用的其他操作。客户端没有必要把REST服务的结构或者动态行为硬编码。

参考

(全文完)