什么是REST?
REpresentational State Transfer (REST) 是一种架构原则,REST定义了应该如何正确地使用Web 标准(例如 HTTP 和 URI)来定义你的服务端接口。其中将 web 服务视为资源,可以由其 URL 唯一标识。RESTful Web 服务的关键特点是明确使用 HTTP 方法来表示不同的操作的调用。
REST要解决什么问题?
网站服务API的早期标准就是SOAP,SOAP的本质还是提供的是异构化接口,虽然有SWDL,但是SWDL只是描述文档,并没有改变“服务异构化API”这个事实。所以基于SOAP的服务五花八门,显然不利于网络时代的通用共享的需求,而“通用共享”就意味着标准化。
REST就是这种标准化需求的产物。
REST的具体技术实现思路就是:以HTTP协议为标准,改造网站API。
REST Web 服务的四个基本设计原则
由于是以HTTP标准为中心,所以REST服务具有HTTP特征,
REST Web 服务,其具体实现应该遵循四个基本设计原则:
1.显式地使用 HTTP 方法
REST 的基本设计原则对典型 CRUD 操作使用 HTTP 协议方法:
POST - 创建资源
GET - 检索资源
PUT – 更新资源
DELETE - 删除资源
统一接口也使得所有理解 HTTP 应用协议的组件能与你的应用交互。通用客户程序(generic client)就是从中受益的组件的例子,例如 curl、wget、代理、缓存、HTTP 服务器、网关还有 Google、Yahoo!、MSN 等等。
2. 目录结构式的 URI
也叫“为所有“事物”定义 ID”,通常,值得被 URI 标识的事物——资源——要比数据库记录抽象的多。例如,一个定单资源可以由定单项、地址以及许多其它方面(可能不希望作为单独标识的资源暴露出来)组成。标识所有值得标识的事物,领会这个观念可以进一步引导你创造出在传统的应用程序设计中不常见的资源:一个流程或者流程步骤、一次销售、一次谈判、一份报价请求——这都是可以被标识的资源。
从对资源寻址的客户端应用程序的角度看,URI 决定了 REST Web 服务将具有的直观程度,REST Web 服务 URI 的直观性应该达到很容易猜测的程度。 将 URI 看作是自身配备文档说明的接口,开发人员只需很少(如果有的话)的解释或参考资料即可了解它指向什么,并获得相关的资源。 为此,URI 的结构应该简单、可预测且易于理解。
实现这种级别的可用性的方法之一是定义目录结构式的 URI。 此类 URI 具有层次结构,其根为单个路径,从根开始分支的是公开服务的主要方面的子路径。 根据此定义,URI 并不只是斜杠分隔的字符串,而是具有在节点上连接在一起的下级和上级分支的树。 例如,在一个收集从 Java 到报纸的各种主题的讨论线程服务中,您可能定义类似如下的结构化 URI 集合:http://www.myservice.org/discussion/2008/12/10/{topic}
根 /discussion 节点之下第一个路径片段是四个数字的年份,第二个路径片断是两个数字的日期,第三个片段是两个数字的月份,最后有一个 /topics 节点。 该节点之下有一系列主题名称,例如闲谈、技术等等,每个主题名称指向某个讨论线程。 在此结构中,只需在 /topics/ 后面输入某个内容即可容易地收集讨论线程。
此示例非常直观。
3.支持 XML、JSON等多种数据传输格式
多数据传输格式支持,减少了各个服务之间数据格式转换的麻烦。
对于网络数据来说,数据的Representation必须是通用类型,而不能用int、string、class这类语言局限型数据格式,所以对于资源来说,就是总要通过某种文本格式反应其内容,文本可以用txt格式表现,也可以用HTML格式、XML格式表现,甚至可以采用二进制格式;图片可以用JPG格式表现,也可以用PNG格式表现;JSON是现在最常用的资源表示格式。
RUI可以用XML、JSON、XHTML等任意一种数据格式来描述、并在网络上传输,这使得服务可由运行在不同平台和设备上并采用不同语言编写的各种各样的客户端所使用。 使用 MIME 类型和 HTTP Accept Header 是一种称为内容协商 的机制,这种机制允许客户端选择适合于它们的数据格式,并最小化服务与使用服务的应用程序之间的数据耦合,避免了使用JSON数据格式的客户在JSON和SOAP规定的XML之间的格式转换。
4.无状态性(Stateless)
HTTP 协议从本质上说是一种无状态的协议,客户端发出的 HTTP 请求之间可以相互隔离,不存在相互的状态依赖。基于 HTTP 的 ROA,以非常自然的方式来实现无状态服务请求处理逻辑。对于分布式的应用而言,任意给定的两个服务请求 Request 1 与 Request 2, 由于它们之间并没有相互之间的状态依赖,就不需要对它们进行相互协作处理,其结果是:Request 1 与 Request 2 可以在任何的服务器上执行。
无状态性可以带来两大好处:
1)REST 要求状态要么被放入资源状态中,要么保存在客户端上。或者换句话说,服务器端不能保持除了单次请求之外的,任何与其通信的客户端的通信状态。这样做的最直接的理由就是可伸缩性—— 如果服务器需要保持客户端状态,那么大量的客户端交互会严重影响服务器的压力。
2)服务器集群可以支持无缝请求
无状态约束使服务器的变化对客户端是不可见的,因为在两次连续的请求中,客户端并不依赖于同一台服务器。一个客户端从某台服务器上收到一份包含链接的文档,当它要做一些处理时,这台服务器宕掉了,可能是硬盘坏掉而被拿去修理,可能是软件需要升级重启——如果这个客户端访问了从这台服务器接收的链接,它不会察觉到后台的服务器已经改变了。
关于有状态和无状态的具体描述见:
凌风探梅的博客:https://blog.youkuaiyun.com/Real_Myth/article/details/75645530
REST和SOAP结构上的区别
参考凌风探梅的博客:https://blog.youkuaiyun.com/Real_Myth/article/details/75645530
可以看到,与 REST 架构相比,SOAP 架构图明显不同的是:所有的 SOAP 消息发送都使用 HTTP POST 方法,并且所有 SOAP 消息的 URI 都是一样的,这是基于 SOAP 的 Web 服务的基本实践特征。
REST和SOAP的设计思想区别
结构上的区别还都是表面的浅层区别,其实REST和SOAP的最本质区别在于设计思想。
如果把客户端看做一个组件,webServer看做一个组件,那么网络请求就是这两个组件之间的交互过程,既然是交互,那就必然要有约定,REST和SOAP就是另种不同的约定规范。
那么这两种约定有什么不同呢?也就是说既然SOAP是早期的约定,那为什么又需要一个REST?也就是说SOAP遇到了什么困境呢?
答案就是:SOAP其实是面向过程编程,而不是OOP。
从SOAP的架构图可以看到,客户和SOAP Server之间的约定方式是由SOAP Server完全控制的,也就是说,比如createUser等接口都是SOAP Server限定死的,客户要想访问,就只能使用这些特定的接口。
这样一来,客户的业务代码实际上就受制于特定的SOAP Server服务器,每个SOAP Server规定的接口都是属于他们自己的特有接口,其实就是一个个具体的实现。
可以想象,客户其实是在面向具体编程,同样的业务,如果需要换另一个SOAP Server2,那么客户就不得不重写一套遵守SOAP Server2接口的代码,这样复用性就太差了吧。显然不利于网络服务的共享和普遍访问。
按照设计原则,下一步的解决方案显然就是:组件化、解耦。
组件化就是把客户端和服务端看做两个互不依赖的独立组件,然后为他们之间的交互提供一套标准协议。
反观REST,REST ful接口规范的定义权不既不属于客户,也不属于webServer,而是基于http的一套通用的标准协议,从webServer的观点来看,现在不是说webServer制定规则,而是反过来webServer必须遵守REST规范,这就是所谓的控制反转。
所以一句话,REST就是实现网络服务之间通信的接口标准化。
要搞清楚REST和SOAP的真正区别,还是得从设计模式的角度来进行本质分析,而不能只是简单罗列一大堆现象。
REST是一种架构原则,那么这个架构原则到底是什么样子呢?它和SOAP有什么不一样?
SOAP作为一种RPC调用,也是一种架构原则,这种架构原则是什么呢?
答案就是:SOAP是面向过程的两层架构。
什么意思呢?从设计模式的角度来看,SOAp服务提供的接口(比如Creatuser,getUserByName等)都是实体接口,现在客户端就是直接通过发送这些接口和SOAP服务器通信的,这是啥?这不是就是面向具体实现编程嘛。
客户要想调用服务,就必须使用这些特定的API,也就是说,把特定的服务器API渗透进了客户代码里,这种结构把客户端和SOAP服务的接口死死绑定在一起,如果客户想换另一家服务器B的服务,那就不得不打开代码把所有调用服务器A的API的地方重新修改成服务器B的PAI,其僵化性就不用多说了。
那么相比之下,REST是什么架构呢?
答案就是:REST是面向对象的三层架构。其实更像中介者模式。
什么意思呢?其实REST的目的就是“对客户端和服务器进行解耦”,从设计模式的角度来看,REST架构不是像SOAP那样客户端直接调用服务器的具体服务接口,而是在客户端和服务器之间添加了一个中间层:REST接口,客户端和服务器接口都遵守REST接口规范。这样一来,客户端调用的就不是服务器的特定接口,而是REST标准接口,服务器必须把它的具体接口转换成REST标准接口,对外进行服务。
REST这样做的价值在哪里呢?
1)通过这个中间的REST标准化规范,实际上实现了客户端和服务器之间的解耦。由于客户端调用的是REST标准接口,如果客户想换另一家服务器B的服务,由于务器B提供的接口依然是REST接口,所以对于客户端来说,API是一样的,显然就不需要再打开代码把所有调用服务器A的API的地方重新修改成服务器B的PAI。
2)而REST标准化规范又具体表现为http协议。所以说,RESTful Web 服务的关键特点是明确使用 HTTP 方法来表示不同的操作的调用。
这种解耦架构,使得REST具有高度的可重用性,可以利用并整合和其他http标准服务(比如负载均衡,缓存,安全代理控制等)协同工作,具有极强的系统可扩展性。
对于REST的误解
一个REST服务必须满足以上四个特征,但是反过来不成立,也就是说,满足以上特征的不一定就是REST服务。
很多人会盲目追新,又对REST的概念和理念一知半解,最后搞出一个半吊子的怪胎,不仅没有设计出优雅规范的API,甚至还引起了更大的麻烦,最后还自我标榜用了流行的RESTful API。
追求时髦的公司经常会有以下场景:一个新启动的项目因为RESTful API起了争执,服务端同学坚持要用RESTful API,而前端同学则认为服务端用RESTful API就会让前端的调用变得更麻烦。最终争议了一下午还是不了了之。有趣的是参与争执的大部分人都不太了解REST是个什么东西。
现在看来,REST在2000年那个时代,确实是超前于时代的。Web开发者社区对于HTTP的设计意图存在着大量的误解,所谓的「Web Services」,其实除了将HTTP作为底层的传输协议外,跟(互联网环境中的)真正的Web没有什么关系,由此导致了对于HTTP的大量低效率的误用,最著名的莫过于SOAP只使用了POST一个操作。这个情况持续一直到2005年Web 2.0的崛起。那个时候,DCOM、EJB、SOAP/WSDL这些RPC风格的架构由于难以满足互联网环境对分布式应用架构设计的约束,与Web自身的架构风格REST相冲突,很难融入到Web之中。
而随着Ruby on Rails这个著名的Web开发框架开始大力支持REST开发之后,一线的Web开发者才真正接触到了REST。然而Rails所支持的REST开发将对资源的操作局限于CRUD(创建、获取、修改、删除)的语义(即,将对资源的CRUD操作映射到 GET/POST/PUT/DELETE四个HTTP方法),这其实是收窄了REST的适用范围。其他编程语言的Web开发框架(例如Java语言的 Struts、Spring MVC等等)也紧接着模仿了Rails的方式开始支持REST开发,然而这更加导致了一线的Web开发者误以为:REST开发就是 通过GET/POST/PUT/DELETE四个HTTP方法对资源执行CRUD操作。甚至还有很多仅仅使用了HTTP,而没有使用SOAP的Web服 务API,都自称是REST风格(RESTful)的API。
对于什么才是真正的REST风格的误解是如此之多,而将REST作为一个营销噱头的挂羊头卖狗肉者也是如此之多,以至于REST的创造者Fielding终于忍无可忍了。2008年10月Fielding写了一篇博客,做出了一个非常明确的断言:REST APIs must be hypertext-driven!(REST API必须是超文本驱动的!)。超文本驱动这个理念变成了一个缩写词HATEOAS,。其实超文本驱动(Hypertext Driven)的理念才是REST架构风格最核心的理念,也是REST风格的架构达到松耦合目标的根本原因。
对REST的理解程度的3级度量模型
引用Richardson所提出来的REST成熟度模型,来度量对REST的误解程度。
第一级:1个URI + POST
像SOAP那样,只是使用一个URI作为一个服务端口,也只使用一个HTTP方法传输数据。这种做法相当于把HTTP这个应用层协议降级为传输层协议用,《REST实战》也一再强调HTTP是一种应用协议而不是传输协议。再好一点就是使用多个URI,然而不同的URI只是作为不同的调用入口,与此同时只使用同一个HTTP方法传输数据。最常见的错误就是在URI中包含动词,比如URI http://example.com/getOrder?orderId=1234,其实「资源」表示一种实体,所以应该是名词,动词应该放在HTTP协议中。而与此同时URI也有可能破坏HTTP GET的安全性和幕等性,比如某个客户端在http://example.com/updateOrder?id=1234&coffee=latte上执行GET(而不是POST),就能创建一笔新的咖啡订单(一个资源),按理来说GET请求不能改变服务的任何状态。
第二级: URI+HTTP四大方法
达到这一级别的开发者,知道使用多个URI,让不同的URI代表不同的资源(注意多个URI可能指向同一个Resource,而一个URI不能指向不同Resource。),同时使用多个HTTP方法操作这些资源,例如使用POST/GET/PUT/DELET分别进行CRUD操作。这时候HTTP头和有效载荷都包含业务逻辑,例如HTTP方法对应CRUD操作,HTTP状态码对应操作结果的状态。我们现在看到的大多数所谓RESTful API做到的也就是这个级别。《REST实战》的译者也谈到:悟性差的人,理解到CRUD式Web服务就满足了。而悟性好的人,可以彻底理解超文本驱动,甚至是与REST关系密切的语义网,最终达到 REST开发的最高境界。
第三级:HATEOAS,超文本驱动
根据Roy的严格规定,超媒体(hypermedia)是REST的先决条件。任何其他东西不应该自我标榜为REST。
要理解HATEOAS这个概念,先要解释什么是超媒体:我们已经知道什么是多媒体(multimedia),以及什么是超文本(hypertext)。其中超文本特有的优势是拥有超链接(hyperlink)。如果我们把超链接引入到多媒体当中去,那就得到了超媒体,因此关键角色还是超链接。也就是说,超媒体就是引用了超链接的多媒体。使用超媒体作为应用引擎状态,意思是应用引擎的状态变更由客户端访问不同的超媒体资源驱动。
超媒体的核心概念就是所谓的元素,而这些相互链接的资源实际上描述了一个协议,即引导我们达成某个目标的一系列步骤,例如订购一杯咖啡所需要的点单、付款、取咖啡等等。这就是超媒体的本质:经由资源之间的链接,我们改变整个应用的状态,即超媒体转换了分布式应用的状态。什么意思呢?比如订购咖啡,你只有先链接到“点单”,然后才能链接到付款,最后才能到达取咖啡这个链接,最终完成这一系列步骤后,才能喝到咖啡,而每一个步骤都是前一个链接引导的。需要注意的是,服务器和消费者两者间交换的是资源状态的表述,而不是应用的状态,被转移的表述中包括了反应应用状态的链接。
让我们来看个实例,来具体感受一下什么是超媒体:
GET https://api.example.com/profile
返回的超媒体信息如下:
{
“name”: “Steve”,
“picture”: {
“large”: “https://somecdn.com/pictures/1200x1200.png”,
“medium”: “https://somecdn.com/pictures/100x100.png”,
“small”: “https://somecdn.com/pictures/10x10.png”
}
由于在响应中包含了超链接地址,因此使用该API的客户端就能够自由选择要下载怎样的信息。这些链接告知了客户端有哪些选择,并且它们的地址在哪里。因此在这里我们无需同时返回三个不同版本的用户档案图片,我们所做的只是告诉客户端有三种可用的图片尺寸可以选择,并且告诉客户端能够在哪里找到这些图片。这样一来,客户端就能够根据不同的场景,做出符合自身需要的选择。而且,如果客户端只需要一种格式的图片,那就无需下载全部三种版本的图片了。这样一来可谓一箭三雕:既减少了网络负载,又增进了客户端的灵活性,更增进了API的可探索性。
REST 的优势
RESTful Web 服务使用标准的 HTTP 方法,可以带来许多好处,从大的方面来讲:因为本身遵守标准化的 HTTP 操作方法,所以就可以利用其他的标准化技术,如 URI,HTML,XML 等,将会极大提高系统与系统之间整合的互操作能力。
与SOAP相比,REST 服务的主要优势在于:
REST是高度可重用的,因为依赖基本 HTTP 协议,所以可以利用并整合和其他http标准服务协同工作。主要表现在以下几个方面:
-
负载均衡支持
分布式的服务器集群要求每个服务器提供的服务需要发送完整、独立的请求;也就是说,发送的请求包括所有需要满足的数据,以便中间服务器中的组件能够进行转发、路由和负载平衡,而不需要在请求之间在本地保存任何状态。
完整、独立的请求不要求服务器在处理请求时检索任何类型的应用程序上下文或状态。 REST Web 服务应用程序(或客户端)在 HTTP Header 和请求正文中包括服务器端组件生成响应所需要的所有参数、上下文和数据,由于REST的无状态,客户端发出的 HTTP 请求之间可以相互隔离,不存在相互的状态依赖。对于分布式的应用而言,任意给定的两个服务请求 Request 1 与 Request 2, 由于它们之间并没有相互之间的状态依赖,就不需要对它们进行相互协作处理,其结果是:Request 1 与 Request 2 可以在任何的服务器上执行,这样的应用很容易在服务器端支持负载平衡 (load-balance)。 -
代理服务器支持
由于数据包是遵守标准thhp协议,所以可以利用代理服务器对数据包做安全控制。
由于RESTful风格的服务是面向资源的,所以认证机制尤为重要。例如一个隐私资源,只有本人或其他少数有权限的用户有资格看到,不通过权限认证机制对资源做一层限制,那么所有资源都将以公开方式暴露出来,很不合理的,同样也很危险。
所以说,REST开发其实是在开发反黑客软件。
安全控制最通行的做法是:所有从客户端Client发出的HTTP请求都经过代理服务器(Proxy Server)。代理服务器制定安全策略:所有经过该代理的访问资源的请求只具有读取权限,而像具有写权限的PUT/DELTE是不被允许的。
也就是说,安全控制的基石就是“必须知道客户的操作类型”。
对于SOAP,如果我们想借助于既有的代理服务器进行安全控制,会比较尴尬。因为所有的SOAP消息,代理服务器只能看到类似
(http://localhost:8182/v1/soap/servlet/messagerouter/ :getUserByName, HTTP POST)这样的信息,只根据这样的信息,代理服务器是无法知道客户当前请求的是什么资源以及客户进行什么样的操作。如果代理服务器想知道当前的HTTP请求具体做的是什么,必须对SOAP的消息体解码,这样的话,意味着要求第三方的代理服务器需要理解当前的SOAP消息语义。既然代理服务器无法获取足够的信息,安全控制就无从谈起了。
而相比之下,REST请求类似于(http://localhost:8182/v1/users/{username},DELETE)这样,代理服务器可以获取到足够的信息,安全控制实现起来就比较容易了。 -
缓存服务器支持
同样由于数据包是遵守标准thhp协议,所以可以利用http协议本身就有的缓存cache能力。
HTTP协议带条件的HTTP GET请求 (Conditional GET) 本来就是被设计用来节省客户端与服务器之间网络传输带来的开销,这也给客户端实现Cache机制 ( 包括在客户端与服务器之间的任何代理 ) 提供了可能。
那么基于HTTP协议的REST的应用当然就可以充分地挖掘HTTP协议对缓存支持的能力。当客户端第一次发送HTTP GET请求给服务器获得内容后,该内容可能被缓存服务器(Cache Server) 缓存。当下一次客户端请求同样的资源时,缓存可以直接给出响应,而不需要请求远程的服务器获得。而这一切对客户端来说都是透明的。
而对于SOAP,缓存服务器根本不知道那个资源正在被请求,更不用谈进行缓存处理。
以上的几个方面,对 SOAP 与 REST 进行了对比,可以看到,基于 REST 构建的系统其系统的扩展能力要强于 SOAP,基于 REST 设计和实现的简单性和强扩展性,有理由相信,REST 将会成为 Web 服务的一个重要架构实践领域。
总之一句话:SOAP是面向过程的,REST是面向对象的。
SOAP 服务是按照面向方法的方法论来设计的,需要服务提供者清楚的给出每个方法的名称、输入参数、输出详细描述、绑定等等。
REST 服务是面向资源的,服务提供者只需要告诉用于定位到服务的 URL template 以及要实例化这个 template 所有的参数描述。
REST设计上的难点和误区
在REST中最困难的地方体现在URI资源的设计。
怎样构建一个REST FUL服务器?
RESTful架构的设计主要是资源的创建,资源表述是REST中很重要的一个方面,它是关于客户端和服务器端针对某一资源是如何通信的。
难点1: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,资源不能是动词,但是可以是一种服务:
POST /transaction HTTP/1.1
Host: 127.0.0.1
from=1&to=2&amount=500.00
难点2:面向资源≠面向单表操作
注意,面向资源不等于面向单表操作。不知道为什么很多人会把资源对应到数据库里的单张表。其实他们没有任何关系。资源可以是一个文件,可以是缓存里的数据,也可以是数据库里多张表聚合的结果。比如用户这个资源。通常我们设计数据库的时候出于性能或方式的考虑用户的信息不会放在一张表里。但是在API设计的时候用户就是一个资源,这个资源的数据有可能来自一张表也有可能是多张表,甚至缓存。
难点3:复杂业务场景如何设计
跟万物皆对象一样,使用「万物皆资源」的思想设计实际项目中的API时,经常会遇到一个问题就是「这玩意到底是个什么资源?………………算了,我就直接写吧,不管什么风格了」
比如,登录(login)和登出(logout)应该怎么REST化?
比如,多条件复合搜索条件太多在GET里写不下怎么办?
比如,批量资源的操作id多到URL都写不下,难道要写几千个UPDATE或DELETE?
其实在真正理解了REST后,这些都不是什么无解的难题,如果你觉得用REST无解,那只能说明你还没真正理解,抽象成资源的能力还不到家:
登录(login)和登出(logout)其实本质上只是对session资源的创建和删除;
//登录——使用HTTP POST请求 POST /localhost/session 创建一个session资源
//登出——使用HTTP DELETE请求 DELETE /localhost/session删除一个session资源
对于“多条件复合搜索”
我们可以把search本身抽象成资源,使用POST创建,如果不需持久化,可以直接在Response中返回结果,如果需要(如翻页、长期缓存等),直接保存搜索结果并303跳转到资源地址就行了:
POST /localhost/search //POST创建资源search
至于“批量操作id多到连url都写不下的请求”场景
应该创建task,用GET返回task状态甚至执行进度;
POST /localhost/task //HTTP POST创建Task
GET /localhost/task //HTTP GET获取TASK执行结果
REST缺点与适用场景
任何一门技术或者思想都有其优缺点,虽然其诞生的初衷都是为了解决我们的问题,而不是带来更大的灾难。REST同样如此。它的优点很明显,优雅、规范,行为和资源分离,更容易理解。但简单高效是对于用户来说的,而对于服务开发者而言,简单就意味着高度复杂的抽象设计,对后端开发人员的要求非常高。
它面向资源,这种设计思路是反程序员直觉的,因为在本地业务代码中仍然是一个个的函数,是动作,但表现在接口形式上则完全是资源的形式,对于后端开发人员要求高,有些业务逻辑难以被抽象为资源的增删改查,所以要求后端开发人员有高度的逻辑抽象能力。甚至有些时候RESTful其实是个效率很低的东西,为了实现一个资源,你需要定义属于它的一套方式,如果要联合查询又会要求对其衍生或定义一个新的资源。它提供的接口一般是“粗”粒度的,它通常返回的都是完整的数据模型,难以查询符合特殊要求的数据,有些特殊的业务要比普通的API需要更多次HTTP请求。
长于纯数据提供,不适合业务处理
所以REST适合于资源/数据提供型场景(比如百度地图,商品查询),而不适合于业务逻辑复杂的场景(比如银行等不适合暴露资源的业务)。
REST面对的疑问跟当年刚开始流行面向对象时的情况是一样的。它适合很多情况,但并不适合所有情况。它更适合与一些开放平台API,如新浪微博、GitHub、京东、淘宝开放平台等,开放API之所以开放,就是因为它不知道你到底需要什么返回结果,既然不知道,那么我干脆都返回给你,在客户端自由组合成自己想要的数据。而对于内部开发,有其局限性,内部开发由于需求非常明确,有些时候出于性能或灵活性的考虑,服务端简单粗暴的丢出来完整的数据模型由客户端自己处理显然是不合适的。
对于一些内部的开发,适合用RESTful API的我们仍然可以用,对于一些不合适的,我们仍然可以借鉴一些RESTFul中的优点,来设计我们的API。比如简洁的URI(每个人看到一坨超长的API地址,内心都是拒绝的),充分利用HTTP状态码等。
其实REST规范最终还是为了开发者和软件产品服务的,如果它能带来便利、减少混乱,就值得用;反之,如果带来的麻烦比解决的还多,跟风追流行就不可取了。其它任何技术也是如此!