什么是RESTful架构?
RESTful 架构,是目前最流行的一种互联网软件架构。它基于REST原则,结构清晰、符合标准、易于理解、扩展方便,正得到越来越多网站的采用。
在传统上,软件和网络是两个不同的领域,很少有交集;软件开发主要针对单机环境,网络则主要研究系统之间的通信。互联网的兴起,使得这两个领域开始融合,越来越多的人开始意识到,网站即软件,而且是一种新型的软件。
2000年,Roy Thomas Fielding(HTTP 协议的主要设计者、Apache 基金会的第一任主席)在他的博士论文中提出了【REST】这一概念;对于论文的写作目的,他有如下的描述:
我这篇文章的写作目的,就是想在符合架构原理的前提下,理解和评估以网络为基础的应用软件的架构设计,得到一个功能强、性能好、适宜通信的架构。
Fielding将他对互联网软件的架构原则,定名为 REST,即 Representational State Transfer 的缩写。这里对这个词组的翻译是「表现层状态转化」。
如果一个架构符合REST原则,就称它为 RESTful 架构;也就是说,只要我们弄清楚了 Representational State Transfer 这个词组的含义,也就弄明白了 RESTful 架构是怎么一回事。
这里先对 REST 原则进行描述,再对 RESTful API 的设计方法展开讨论。
REST 架构原则
前面提到,REST 其实是【Representational State Transfer】词组的缩写,我们可以从下面三个部分入手,理解这个词组的含义:
资源(Resource)
REST 可译作“表现层状态转换“,其实对主语还进行了一层省略:这里的“表现层”指的就是「资源(Resource)」的「表现层」。
在 REST 架构原则看来,网络上的每个具体信息都是一个实体,也就是资源;资源可以是一个文本、一段文字、一张图片、一种服务,总之就是一个具体的实体。我们用一个 URI (唯一资源标示符)来唯一指向特定的某个资源。
所谓的“上网”,其实就是与网络上的“资源”进行交互,对“资源”的 uri 进行调用。
表现层(Representation)
上面提到,「Resource」是网络上某种信息的实体,但即使对于同一种资源,我们会希望能够它能以不同的形式呈现在用户面前。而这种将「资源」具体呈现出来的形式,便称为表现层(Representation)。
例如,现有一段文字信息,对于这个「文字资源」,在进行数据传输时我们希望它能够以 JSON 进行传输,而在存储时我们又可能希望它能够以 XML 或是 txt 形式存储在本地。
对于一个资源,我们用一个 URI 来标示它的实体,但 URI 不能标示资源的形式。套用上面的例子,文字资源的 uri 只能让服务器或客户端准确地找到这个资源,但服务器和客户端不知道这个资源是哪种形式的。也就是说,用户真正需要看到的并不仅仅是资源,而是资源的特定 Representation。
很多网站直接在 URL 中直接指定资源的表现形式,例如 CSDN 和博客园,每篇博客的 URL 后都可以看到「.html」的后缀,严格意义上来说这样的后缀名是不规范的:因为 URI 应该只代表资源的地址,「.html」后缀代表文字信息的格式,属于「表现层」的范畴;一个资源的具体表现形式,应该在 HTTP 请求的头信息中,使用 Accept 和 Content-Type 字段来指定。
下面的 ajax 代码就是一个很好的例子,它通过 Content-Type 字段指定 HTTP 的 body 是一个 JSON 格式、且采用 utf-8 字符集编码的文本信息:
$.ajax({ type: "POST", url: "/users", contentType: "application/json;charset=utf-8", data:{ "name": "test", "pwd": "123456" }, dataType: "json", success:function (message) { alert("提交成功"+JSON.stringify(message)); }, error:function (message) { alert("提交失败"+JSON.stringify(message)); } });
状态转换(State Transfer)
了解了「Resource」和「Presentation」后,我们便可以按照自己的需要获取到我们理想状态的数据,但现实生活中,用户访问网站实际上是一个客户端和服务器之间的互动过程,这个过程中双方不断的建立连接进行通信,势必会涉及到数据和状态的变化。
这里涉及到「状态」这个可能引起困惑的名词,我们将其和 REST 原则中的「无状态通信原则」放在一起讨论。
无状态通信原则
首先需要说明的是,这里说的无状态通信原则,并不是说客户端应用不能有状态,而是指服务端不应该保存客户端状态。同时,互联网的基石,HTTP 协议,也是一个「无状态」协议。
「状态」指的是什么?
实际上,「状态」应该区分为应用状态和资源状态,客户端负责维护应用状态,而服务端维护资源状态。「应用状态」便是用户在客户端进行的种种业务操作,例如对数据的更新操作;而在客户端,当对一个数据进行诸如更新等操作后,我们就可以说「资源状态」发生了改变。
什么是「无状态通信」?
从名字的意义相近,在「无状态通信」中,客户端与服务端的交互必须是无状态的,并在每一次请求中包含处理该请求所需的一切信息。
「无状态」的交互
这样以来,服务端不需要在请求间保留应用状态,只有在接受到实际请求的时候,服务端才会关注应用状态,并且根据应用状态来令资源状态作出相应的改变。
每次请求中包含这次请求所需的所有信息
这个比较好理解,应为服务端不会保存客户端的状态,所以每次请求对服务端来说都是独立存在的;如果当前请求中的信息不足以让服务端完成这个请求,那么这个请求将无效。
这种无状态通信原则,使得服务端和中介能够理解独立的请求和响应。 在多次请求中,同一客户端也不再需要依赖于同一服务器,方便实现高可扩展和高可用性的服务端。
当然,我们也有需要违法无状态通信的业务场景,例如「登录」操作,如果是遵循无状态通信,那么用户每次进行业务操作都需要重新进行登录,无疑是非常反人类的体验。在这种类似的场景中,我们可以使用「session」和「cookie」来跟踪和保存会话状态。
看到这里,状态转移应该就很好理解了:在客户端和服务器进行交互时,如果客户端的「应用状态」发生变化(如用户注册一个新账号提交了一个表单数据),程序就需要让服务器的「资源状态」按照客户端要求发生「状态转换」(也就是 CREATE 一个新的账号数据)。而这种转换是建立在表现层之上的,所以是「表现层状态转换」,也就是「REST」。
那么,对「REST」这个词组大家应该有一个大致的了解了,那再看看不难猜到「REST(表现层状态转换)」架构原则是做什么的了:对程序员(针对资源表现层的)程序中编写的状态转换方法作出约束,建立一个大家都应该去遵守的标准。
而在当今的互联网架构下,客户端能用到的手段,只有 HTTP 协议。简单来说,就是HTTP协议里面,四个表示操作方式的动词:GET、POST、PUT、DELETE。它们分别对应四种基本操作:GET用来获取资源,POST用来新建资源(也可以用于更新资源),PUT用来更新资源,DELETE用来删除资源。更具体的便是 RESTful API 设计考虑的内容了,我们会在后续进行讨论。