REST,Representational State Transfer,即表现层状态转换,指的是一种为了信息能在互联网上顺利传递而设计的软件架构风格。对,请注意,SOAP 是协议,但 REST 是风格,而非协议或标准,至于 HTTP,它是 REST 风格的重要载体。重要,但不是唯一,因为载体并不只有 HTTP 一个,比如还有 HTML 和 XML,它们恰当地互相配合,组合在一起,来贯彻和体现 REST 的风格。
REST 的核心要素包括资源、表现层和状态转换这三个部分。:
1.协议
我们将使用 HTTP 协议,在加密的情况下,协议是 HTTPS,但这对我们的实现来说没有什么区别。
2. URL
通常来说,这个 URL 要包括域名、版本号以及实体名称,而这个 URL 整体,代表了 REST中的一类或一项“资源”。比如说:
请注意其中的实体名称,它往往是一个单纯的名词,并且以复数形式出现。这里提到了 URL,我想给经常混用的 URL、URI 做个简要的说明:URL 指的是 UniformResource Locator,URI 指的是 Uniform Resource Identifier,前者是统一资源定位符,后者是统一资源标识符。Identifier 可以有多种形式,而 locator 只是其中一种,因此URI 更宽泛,URL 只是 URI 的其中一种形式。当我们提到一个完整的地址,例如 www.google.com,它就是 URL,因为它可以被“定位”,它当然也是 URI;但是如果我们只提到上面地址的一个片段,例如www.google.com,那么由于缺少了具体协议,我们无法完成完整的定位,因此这样的东西只能被叫做一个标识符,故而只能算 URI,而非 URL。
3.方法
HTTP 的方法反映了这个接口上将执行的行为,如果用自然语言描述,它将是一个动词。比如说,给图书馆添加一本图书,那么这个行为将是“添加”。在以 REST 风格主导的设计中,我们将使用这样的 HTTP 方法来代表增删改查(CRUD)的不同动作:
幂等性指的是对服务端的数据状态,执行多次操作是否和执行一次产生的结果一样。从表格中你可以看到,创建资源单位不是幂等的,执行多次就意味着创建了多个资源单位,而其它操作都是幂等的。通常来说,幂等操作是可以被重试而不产生副作用的。安全性指的是该操作是否对服务端的数据状态产生了影响。从表格中可以看到,获取资源的操作是安全的,不会对资源数据产生影响,但是其它操作都是不安全的。一定条件下,安全操作是可以被缓存的,而不安全的操作,必定对服务端的状态产生了影响,这体现了REST 的“状态转换”这一要素。
你看,通过这样的办法,就把 HTTP 的方法和实际对资源的操作行为绑定起来了。当然,还有一些其它方法,比较常见的有:
PATCH:和 PUT 类似,也用于资源更新,但支持的是资源单位的部分更新,并且在资源不存在的时候,能够自动创建资源,这个方法实际使用比较少。
HEAD:这个方法只返回资源的头部,避免了资源本身获取和传输的开销。这种方法很有用,经常用来检查资源是否存在,以及有无修改。
OPTIONS:这个方法常用来返回服务器对于指定资源所支持的方法列表。
4.正文
POST 和 PUT 请求都是有 HTTP 正文的,正文的类型和 Content-Type 的选取有关,比如JSON 就是最典型的一种格式。请不要轻视这里的 Content-Type,从本质上说,它代表了资源的表现形式,从而体现了 REST 定义中的“表现层”这一要素。
利弊
REST 则相反,新接口的学习成本很低,只需要知道资源名称,根据我们熟知的规约,就可以创建出 CRUD 的请求来。但是直到真正发送请求去测试为止,并没有办法百分百确定远程接口的调用是否能工作,或者说,并不知道接口定义上是否有不规范、不合常规的坑在里面。
但是别忘了,有利必有弊。首先,正是因为 REST 只是一个缺乏限制的风格,而非一个严谨的规范,有太多不明确、不一致的实现导致的问题,这些问题轻者给接口调用者带来困惑,重者导致接口调用错误,甚至服务端数据错误。
其次,REST 通过 HTTP 方法实现本身,也受到了 HTTP 方法的局限性制约。比如最常见的GET 请求,有时需要一个复杂的查询条件集合,因此参数需要结构化,而 GET 只支持一串键值对组合的参数传递,无法适应业务需要。对于这样的问题,有一些 workaround,比如使用 POST 消息体来传递查询条件的结构体,但那已经偏离了 REST 的最佳实践,丢失了 GET 本身的优势,也带来了实现不一致等一系列问题。
最后,REST 还存在的一个更本质的问题,资源是它的核心概念,这原本带来了抽象和简洁的优势,但如今也成为了它的桎梏。或者说,前面反复提到的增删改查是它最拿手的本事,可是互联网的需求是千变万化的,远不只有简单的增删改查。有时需要一个复杂的多步操作,有时则需要一个异步事务(需要回调或者二次查询等等方式来实现),这些都没有一个完美统一的 REST 风格的解决方案。即便实现出来了,也可谓五花八门,同时失去了以往我们所熟知的 REST 的简洁优势。
参考:《全栈工程师修炼指南》 --熊四火