预备知识

121 阅读9分钟

Restful

起源

在没有前后端分离概念之前,一个网站的完成总是“all in one”,在这个阶段,页面、数据、渲染全部在服务端完成,这样做的最大的弊端是后期维护,扩展极其痛苦,开发人员必须同时具备前后端知识。 于是后来慢慢的兴起了前后端分离的思想:即后端负责数据编造,而前端则负责数据渲染,前端静态页面 调用指定 api 获取到有固定格式的数据,再将数据展示出来,这样呈现给用户的就是一个”动态“的过程。

而关于 api 这部分的设计则成了一个问题。如何设计出一个便于理解,容易 使用的 api 则成了一个问题,而所谓的 RESTful 就是用来规范我们的 API 的一种 约束

REST

作为 REST,其实是 Representational State Transfer(表象层状态转变) 三个单词的缩写,它由 Roy Fielding(Fielding 是 HTTP 协议(1.0 版和 1.1 版) 的主要设计者、Apache 服务器软件的作者之一、Apache 基金会的第一任主席) 于 2000 年论文中提出,他在论文中提到:"我这篇文章的写作目的,就是想在符 合架构原理的前提下,理解和评估以网络为基础的应用软件的架构设计,得到一 个功能强、性能好、适宜通信的架构。REST 指的是一组架构约束条件和原则。" 如果一个架构符合 REST 的约束条件和原则,我们就称它为 RESTful 架构。

要理解 RESTful 架构,最好的方法就是去理解 Representational State Transfer 这个词组到底是什么意思,它的每一个词代表了什么涵义。如果你把 这个名称搞懂了,也就不难体会 REST 是一种什么样的设计。

资源(esources)

REST 的名称"表现层状态转化"中,省略了主语。"表现层"其实指的是"资源 "(Resources)的"表现层"。

所谓"资源",就是网络上的一个实体,或者说是网络上的一个具体信息。它 可以是一段文本、一张图片、一首歌曲、一种服务,总之就是一个具体的实在。

要让一个资源可以被识别,需要有个唯一标识,在 Web 中这个唯一标识就是 URI(Uniform Resource Identifier

URI 既可以看成是资源的地址,也可以看成是资源的名称。如果某些信息没 有使用 URI 来表示,那它就不能算是一个资源, 只能算是资源的一些信息而已。

你可以用一个 URI(统一资源定位符)指向它,每种资源对应一个特定的 URI。 要获取这个资源,访问它的 URI 就可以,因此 URI 就成了每一个资源的地址或独 一无二的识别符。

所谓"上网",就是与互联网上一系列的"资源"互动,调用它的 URI

URI 设计技巧

使用 _ 或 - 来让 URI 可读性更好

曾经 Web 上的 URI 都是冰冷的数字或者无意义的字符串,但现在越来越多的 网站使用_或-来分隔一些单词,让 URI 看上去更为人性化。 例如国内比较出名 的开源中国社区,它上面的新闻地址就采用这种风格, 如 www.oschina.net/news/38119/…

使用 / 来表示资源的层级关系 例如上述/git/git/commit/e3af72cdafab5993d18fae056f87e1d675913d08 就表示了一个多级的资源, 指的是 git 用户的 git 项目的某次提交记录,又例 如/orders/2012/10 可以用来表示 2012 年 10 月的订单记录。

使用 ? 用来过滤资源 很多人只是把?简单的当做是参数的传递,很容易造成 URI 过于复杂、难以 理解。可以把?用于对资源的过滤, 例如/git/git/pulls 用来表示 git 项目的 所有推入请求,而/pulls?state=closed 用来表示 git 项目中已经关闭的推入请 求, 这种 URL 通常对应的是一些特定条件的查询结果或算法运算结果。

, 或; 可以用来表示同级资源的关系

有时候我们需要表示同级资源的关系时,可以使用,或;来进行分割。例如哪 天 github 可以比较某个文件在随意两次提交记录之间的差异,或许可以使用 /git/git/block-sha1/sha1.h/compare/e3af72cdafab5993d18fae056f87e1d675913d08;b d63e61bdf38e872d5215c07b264dcc16e4febca 作为 URI。 不过,现在 github 是 使用…来做这个事情的,例如/git/git/compare/master…next。

URI 不应该包含动词

因为"资源"表示一种实体,所以应该是名词,URI 不应该有动词,动词应该 放在 HTTP 协议中。

举例来说,某个 URI 是/posts/show/1,其中 show 是动词,这个 URI 就设计 错了,正确的写法应该是/posts/1,然后用 GET 方法表示 show。

如果某些动作是 HTTP 动词表示不了的,你就应该把动作做成一种资源。比 如网上汇款,从账户 1 向账户 2 汇款 500 元,错误的 URI 是:

POST /accounts/1/transfer/500/to/2 正确的写法是把动词 transfer 改成名词 transaction,资源不能是动词, 但是可以是一种服务

URI 中不宜加入版本号 例如:

http://www.example.com/app/1.0/foo   
http://www.example.com/app/1.1/foo  
http://www.example.com/app/2.0/foo  

因为不同的版本,可以理解成同一种资源的不同表现形式,所以应该采用同 一个 URI。版本号可以在 HTTP 请求头信息的 Accept 字段中进行区分。

表现层(Representation)

"资源"是一种信息实体,它可以有多种外在表现形式。我们把"资源"具体呈 现出来的形式,叫做它的"表现层"(Representation)。
比如,文本可以用 txt 格式表现,也可以用 HTML 格式、XML 格式、JSON 格 式表现,甚至可以采用二进制格式;图片可以用 JPG 格式表现,也可以用 PNG 格式表现。
URI 只代表资源的实体,不代表它的形式。严格地说,有些网址最后的 ".html"后缀名是不必要的,因为这个后缀名表示格式,属于"表现层"范畴,而 URI 应该只代表"资源"的位置。它的具体表现形式,应该在 HTTP 请求的头信息 中用 Accept 和 Content-Type 字段指定,这两个字段才是对"表现层"的描述

状态转化(State Transfer)

访问一个网站,就代表了客户端和服务器的一个互动过程。在这个过程中, 势必涉及到数据和状态的变化。
互联网通信协议 HTTP 协议,是一个无状态协议。这意味着,所有的状态都 保存在服务器端。因此,如果客户端想要操作服务器,必须通过某种手段,让服 务器端发生"状态转化"(State Transfer)。而这种转化是建立在表现层之上的, 所以就是"表现层状态转化"。 客户端用到的手段,目前来说只能是 HTTP 协议。具体来说,就是 HTTP 协议 里面,四个表示操作方式的动词:GET、POST、PUT、DELETE。它们分别对应四种 基本操作:GET 用来获取资源,POST 用来新建资源(也可以用于更新资源),PUT 用来更新资源,DELETE 用来删除资源。GET、PUT 和 DELETE 请求都是幂等的,无 论对资源操作多少次, 结果总是一样的, POST 不是幂等的。

什么是 RESTful 架构

综合上面的解释,我们总结一下什么是 RESTful 架构: 1.架构里,每一个 URI 代表一种资源;
2.客户端和服务器之间,传递这种资源的某种表现层;
3.客户端通过四个 HTTP 动词(get、post、put、delete),对服务器端资 源进行操作,实现”表现层状态转化”。 注意:REST 架构风格并不是绑定在 HTTP 上,只不过目前 HTTP 是唯一与 REST 相关的实例。 所以我们这里描述的 REST 也是通过 HTTP 实现的 REST。

辨析 URI、URL、URN

A Uniform Resource Identifier (URI) 是一个紧凑的字符串用来标示抽象 或物理资源。

一个 URI 可以进一步被分为定位符、名字或两者都是. 术语“Uniform Resource Locator” (URL) 是 URI 的子集, 除了确定一个资源,还提供一种定位 该资源的主要访问机制。

所以,URI = Universal Resource Identifier 统一资源标志符,包含 URL 和 URN,支持的协议有 http、https、ftp、mailto、magnet、telnet、data、file、 nfs、gopher、ldap 等,java 还大量使用了一些非标准的定制模式,如 rmi,jar、 jndi 和 doc,来实现各种不同用途资源在 Internet 上的位置。不管用什么方法表示,只要能定位一个资源,就 叫 URL。

URN = Universal Resource Name 统一资源名称,URN 它命名资源但不指定 如何定位资源,比如:只告诉你一个人的姓名,不告诉你这个人在哪。

对于一个资源来说,URN 就好比他的名字,而 URL 就好比是资源的街道住址。 换句话说,URN 标识了一个资源项目,而 URL 则提供了一种找到他的方法。 比如同时指定基本的获取机制和网络位置。举个例子, example.org/wiki/Main_P… 的资源,这个资源的表现形式是 HTML 和相关的代码。而获取这个资源的方法是 在网络中从一个名为 example.org 的主机上,通过 HTTP( Hypertext Transfer Protocol)获得。

而 URN 则是一种在特定的名称空间中通过通过名字来标识资源的 URI。当讨 论一种资源而不需要知道它的位置或者如何去获得它的时候,就可以使用 URN。 例如,在 International Standard Book Number (ISBN)系统中,* ISBN 0-486-27557-4 用来指定莎士比亚的作品《罗密欧与朱丽叶》的一个特定版本。 指示这一版本的 URN 是 urn:isbn:0-486-27557-4*,但是如果想要获得这个版本 的书,就需要知道它的位置,这样就必须知道它的 URL。