工整与自由的风格之争:SOAP和REST
概念
SOAP,Simple Object Access Protocol,即简单对象访问协议,定义了数据对象传输的格式,以便在网络的节点之间交换信息。你可能会问,HTTP 不就是干这事的吗?其实,它们都在 OSI 7 层模型的应用层上,但却互不冲突,SOAP 并不依赖于 HTTP 而存在,而且它们可以互相配合。
HTTP 负责信息的传输,比如传递文本数据,关心的是消息的送达,但却不关心这个数据代表着什么。这个数据可能本来是一个内存里的对象,是一篇文章,或者是一张图片。但是 SOAP 恰恰相反,它关心的就是怎样把这个数据给序列化成 XML 格式的文本,在传输到对端以后,再还原回来。
REST,Representational State Transfer,即表现层状态转换,指的是一种为了信息能在互联网上顺利传递而设计的软件架构风格。对,请注意,SOAP 是协议,但 REST 是风格,而非协议或标准,至于 HTTP,它是 REST 风格的重要载体。重要,但不是唯一,因为载体并不只有 HTTP 一个,比如还有 HTML 和 XML,它们恰当地互相配合,组合在一起,来贯彻和体现 REST 的风格。
SOAP 和 REST,由于概念层次上的不同,其实原本是无法放到一起比较的,但是当我们旨在风格层面上讨论 SOAP 和 REST 的时候,这件事却变得可行而有趣了。
SOAP
这是一个最简单的给图书馆添加一本书的 XML 消息体:
<?xml version="1.0" encoding="UTF-8"?>
<soap:Envelope
xmlns:soap="https://www.w3.org/2003/05/soap-envelope/"
soap:encodingStyle="https://www.w3.org/2003/05/soap-encoding">
<soap:Body xmlns:b="...">
<b:CreateBook>
<b:Name>...</m:Name>
<b:Author>...</m:Author>
...
</b:CreateBook>
</soap:Body>
</soap:Envelope>
WSDL,Web Service Description Language:
WSDL 用于描述一个 Web Service,说白了,就是用来说明某个 Web 服务该怎样使用,有怎样的接口方法,支持怎样的参数,会有怎样的返回。由于支持 SOAP 的服务端接口是经常使用 WSDL 来描述,因此我们才看到它们总被放在一起讨论,于是在这种情况下,WSDL 常常被形容成 SOAP 服务的使用说明书,但是请注意,本质上它们之间不存在依赖关系。
REST
REST 的核心要素包括资源、表现层和状态转换这三个部分。我们把前面客户端发送请求的过程使用 REST 风格再来实现一遍,你将看到这三个要点是怎样体现出来的:
资源表现层状态转换.
协议
我们将使用 HTTP 协议,在加密的情况下,协议是 HTTPS,但这对我们的实现来说没有什么区别。
URL
通常来说,这个 URL 要包括域名、版本号以及实体名称,而这个 URL 整体,代表了 REST 中的一类或一项“资源”。比如说:
https://xxx/v1/books
- 请注意其中的实体名称,它往往是一个单纯的名词,并且以复数形式出现。
URL, URI 区别:
- URL 指的是 Uniform Resource Locator, 统一资源定位符
- URI 指的是 Uniform Resource Identifier, 统一资源标识符
Identifier 可以有多种形式,而 locator 只是其中一种,因此 URI 更宽泛,URL 只是 URI 的其中一种形式。
当我们提到一个完整的地址,例如 https://www.google.com, 它就是 URL,因为它可以被“定位”,它当然也是 URI;但是如果我们只提到上面地址的一个片段,例如 www.google.com,那么由于缺少了具体协议,我们无法完成完整的定位,因此这样的东西只能被叫做一个标识符,故而只能算 URI,而非 URL。
方法
HTTP 的方法反映了这个接口上将执行的行为,如果用自然语言描述,它将是一个动词。比如说,给图书馆添加一本图书,那么这个行为将是“添加”。在以 REST 风格主导的设计中,我们将使用这样的 HTTP 方法来代表增删改查(CRUD)的不同动作:
image.png- 幂等性指的是对服务端的数据状态,执行多次操作是否和执行一次产生的结果一样。从表格中你可以看到,创建资源单位不是幂等的,执行多次就意味着创建了多个资源单位,而其它操作都是幂等的。通常来说,幂等操作是可以被重试而不产生副作用的。
- 安全性指的是该操作是否对服务端的数据状态产生了影响。从表格中可以看到,获取资源的操作是安全的,不会对资源数据产生影响,但是其它操作都是不安全的。一定条件下,安全操作是可以被缓存的,而不安全的操作,必定对服务端的状态产生了影响,这体现了 REST 的“状态转换”这一要素。
全栈系统的设计和优化都需要紧密围绕幂等性和安全性进行,这是两个非常重要的概念,在我们后续的学习中,你还会反复见到它们,并和它们打交道。
还有一些其它方法:
- PATCH:和 PUT 类似,也用于资源更新,但支持的是资源单位的部分更新,并且在资源不存在的时候,能够自动创建资源,这个方法实际使用比较少。
- HEAD:这个方法只返回资源的头部,避免了资源本身获取和传输的开销。这种方法很有用,经常用来检查资源是否存在,以及有无修改。
- OPTIONS:这个方法常用来返回服务器对于指定资源所支持的方法列表。
正文
POST 和 PUT 请求都是有 HTTP 正文的,正文的类型和 Content-Type 的选取有关,比如 JSON 就是最典型的一种格式。请不要轻视这里的 Content-Type,从本质上说,它代表了资源的表现形式,从而体现了 REST 定义中的“表现层”这一要素。
REST 风格的 POST 请求实现就会变成这样:
POST /v1/books HTTP/1.1
HOST: ...
Content-Type: application/json
{
"name": "...",
"author": "...",
...
}
风格之争
SOAP 明显是更“成熟”的那一个。它在数据传输的协议层面做了更多的工作,藉由 XML schema,它具备更严格的检查和校验,配合 WSDL,在真正发送请求前,几乎就对所有远程接口事无巨细的问题有了答案。但是,它的复杂度令人望而生畏,也是它最受人诟病的地方。
REST 则相反,新接口的学习成本很低,只需要知道资源名称,根据我们熟知的规约,就可以创建出 CRUD 的请求来。但是直到真正发送请求去测试为止,并没有办法百分百确定远程接口的调用是否能工作,或者说,并不知道接口定义上是否有不规范、不合常规的坑在里面。
扩展阅读
- W3Cschool 上的 SOAP 教程,如果你对 SOAP 不够熟悉,那么你可以参考这个简明扼要的教程。
- 【基础】REST API Tutorial,REST 的教程很多,这是我觉得非常简洁和清晰的一个。
- ProgrammableWeb 上的 Web API 列表,排名最靠前的 10 个 API,其中有 9 个的架构风格都是 REST,这也从侧面应证了 REST 在互联网的趋势。
- REST 和 SOAP:谁更好,或者都好?这是一篇内容精悍的译文,分别介绍了适合 REST 和 SOAP 的场景。