一、概念及特点
REST(Representational State
Transfer)是代表状态传输的缩写,它代表了分布式超媒体系统的体系结构风格,它是一种针对网络应用的设计和开发方式,可以降低开发的复杂性,提高
系统的可伸缩性。REST提出了一些设计概念和准则:
1.网络上的所有事物都被抽象为资源(resource);
2.每个资源对应一个唯一的资源标识(resource identifier);
3.通过通用的连接器接口(generic connector interface)对资源进行操作;
4.对资源的各种操作不会改变资源标识;
5.所有的操作都是无状态的(stateless)。
对于当今最常见的网络应用来说,resource identifier是url,generic connector
interface是HTTP,第4条准则就是我们常说的url不变性。这些概念中的resouce最容易使人产生误解。resouce所指的并不是数
据,而是数据+特定的表现形式(representation),这也是为什么REST的全名是Representational State
Transfer的原因。举个例子来说,“本月卖得最好的10本书”和“你最喜欢的10本书”在数据上可能有重叠(有一本书即卖得好,你又喜欢),甚至完
全相同。但是它们的representation不同,因此是不同的resource。
REST之所以能够简化开发,是因为其引入的架构约束,比如Rails
1.2中对REST的实现默认把controller中的方法限制在7个:index、show、new、edit、create、update和
destory,这实际上就是对CURD的实现。更进一步讲,Rails(也是当今大部分网络应用)使用HTTP作为generic
connector interface,HTTP则把对一个url的操作限制在了4个之内:GET、POST、PUT和DELETE。
REST之所以能够提高系统的可伸缩性,是因为它强制所有操作都是stateless的,这样就没有context的约束,如果要做分布式、做集
群,就不需要考虑context的问题了。同时,它令系统可以有效地使用pool。REST对性能的另一个提升来自其对client和server任务的
分配:server只负责提供resource以及操作resource的服务,而client要根据
resource中的data和representation自己做render。这就减少了服务器的开销。
REST特点
- 客户端-服务器:拉风格的交互模式:消费方组件把表示拉出来
- 无状态:每个从客户端到服务器的请求必须包含足够的信息使得服务器理解该请求,不需要服务器上存储的上下文信息
- 缓存:为了提高网络效率,响应应该可以被标示成可缓存的或是不可缓存的
- 统一的接口:所有资源通过通用的接口访问(HTTP GET, POST, PUT, DELETE)
- 命名资源:系统由通过URL命名的资源组成
- 互连的资源表示:资源的表示通过URL互相联系起来,从而客户端可以从一个状态转换到另一个
- 层次化的组件:中间件,比如代理服务器,缓存服务器,网关等,可以插入到客户端和资源中间来完成安全和安全等功能
REST设计原则
- 构建REST的关键是识别出所有需要暴露成服务的概念层实体。
- 为每个资源创建URL。
- 对资源进行分类,区分出哪些客户端只能获取表示,哪些是可以修改的。前者使用HTTP GET来访问,后者使用HTTP POST, PUT和DELETE来访问。
- 所有通过HTTP GET访问的资源必须是没有副作用的。
- 没有表示是作为孤岛存在的。在资源表示中放入超链接。
- 逐步的暴露数据。不要在单一的文档中暴露所有数据。提供超链接来获取更多的信息。
- 使用schema来指定响应的格式。
- 说明该服务是使用WSDL文档来调用,而是简单的HTML文档。
REST优点
可以利用缓存Cache来提高相应速度
通信本身的无状态性可以让不同的服务器处理一系列请求中的不同请求,提高服务器可扩展性
浏览器即可作为客户端,简化软件需求
相对于其他叠加在HTTP协议之上的机制,REST的软件依赖性更小
不需要额外的资源发现机制
在软件技术演进中长期的兼容性更好
二、使用REST
REST和MVC的关系。
第一个问题假设REST是我们应该采用的架构,然后讨论如何使用;第二个问题则要说明REST和当前最普遍应用的MVC是什么关系,互补还是取代?
我们先来谈谈第一个问题,如何使用REST。我感觉,REST除了给我们带来了一个崭新的架构以外,还有一个重要的贡献是在开发系统过程中的一种新
的思维方式:通过url来设计系统的结构。根据REST,每个url都代表一个resource,而整个系统就是由这些resource组成的。因此,如
果url是设计良好的,那么系统的结构就也应该是设计良好的。对于非高手级的开发人员来说,考虑一个系统如何架构总是一个很抽象的问题。敏捷开发所提倡的
Test Driven
Development,其好处之一(我觉得是最大的好处)就是可以通过testcase直观地设计系统的接口。比如在还没有创建一个class的时候就
编写一个testcase,虽然设置不能通过编译,但是testcase中的方法调用可以很好地从class使用者的角度反映出需要的接口,从而为
class的设计提供了直观的表现。这与在REST架构中通过url设计系统结构非常类似。虽然我们连一个功能都没有实现,但是我们可以先设计出我们认为
合理的url,这些url甚至不能连接到任何page或action,但是它们直观地告诉我们:系统对用户的访问接口就应该是这样。根据这些url,我们
可以很方便地设计系统的结构。
重申一遍:REST允许我们通过url设计系统,就像Test Driven Development允许我们使用testcase设计class接口一样。
OK,既然url有这样的好处,那我们就着重讨论一下如何设计url。网络应用通常都是有
hierarchy的,像棵大树。我们通常希望url也能反映出资源的层次性。比如对于一个blog应用:/articles表示所有的文章,
/articles/1表示id为1的文章,这都比较直观。遗憾的是,网络应用的资源结构永远不会如此简单。因此人们常常会问这样一个问
题:RESTful的url能覆盖所有的用户请求吗?比如,login如何RESTful?search如何RESTful?
从REST的概念上来看,所有可以被抽象为资源的东东都可以使用RESTful的url。因此对于上面的两个问题,如果login和search可以被抽
象为资源,那么就可以使用RESTful的url。search比较简单,因为它会返回搜索结果,因此可以被抽象为资源,并且只实现index方法就可以
了(只需要显示搜索结果,没有create、destory之类的东西)。然而这里面也有一个问题:search的关键字如何传给
server?index方法显然应该使用HTTP
GET,这会把关键字加到url后面,当然不符合REST的风格。要解决这个问题,可以把每次search看作一个资源,因此要创建create和
index方法,create用来在用户点击“搜索”按钮是通过HTTP
POST把关键字传给server,然后index则用来显示搜索结果。这样一来,我们还可以记录用户的搜索历史。使用同样的方法,我们也可以对
login应用REST,即每次login动作是一个资源。
让我再说明一下我的想法:如果每个用户需求都可以抽象为资源,那么就可以完全使用REST。
由此看来,使用REST的关键是如何抽象资源,抽象得越精确,对REST的应用就越好。因此,如何改变我们目前根深蒂固的基于action的思想是最重要的。
三、REST与MVC
REST会取代MVC吗?还是彼此是互补关系(就像AOP对于OOP)?答案是It
depends!。当然,这是非常理想的论断。可能我们无法找到一种方法可以把所有的用户需求都抽象为资源,因为保证这种抽象的完整性(即真的是所有需求
都可以)需要形式化的证明。而且即使被证明出来了,由于开发人员的能力和喜好不同,MVC肯定也会成为不少人的首选。但是对于希望拥抱REST的人来说,
这些都没有关系。只要你开发的系统所设计的问题域可以被合理地抽象为资源,那么REST就会成为你的开发利器。
到目前为止,传统的Java Web MVC框架(Struts、WebWork、Spring
MVC、etc.)还无法很好地支持REST风格的架构设计。它们在设计之初时基本上都是围绕着基于HTML表单的交互模式来设计的,View的粒度难以
达到单个页面以下。不能把响应Ajax请求而返回的XML/JSON/纯文本格式的数据简单地认为是Web
MVC框架中的View,实际上这个时候这些数据的语义已经与传统的Web MVC架构中的View的语义相距甚远。
传统的Web MVC框架一个最大的问题是它们看待URL的方式与REST有很大的差别。REST把服务器端所有的URL都当作是抽象的资源(相当于是面向对象设计中的接口),虽然Web MVC也强调不应该将硬编码的URL(例如:http://www.xxx.com/yyy/zzz/abcd.jsp
)
直接暴露出来,而应该通过某个 Controller来暴露,将这个页面配置为Controller的一个View,但是Web
MVC框架并没有有意识地将URL当作抽象的资源来看待和设计。还有一个较为严重的问题是传统的Web
MVC框架基本上都只支持GET和POST两种HTTP方法,而不支持PUT和DELETE方法,而Servlet
API是支持上述所有的HTTP方法的(支持doPut和doDelete方法)。好在不需要我们亲自来做这个事情,已经有一些Java的服务器端框架可
以支持REST了。例如restlet(http://www.restlet.org
)
四、REST与Ajax
传统的服务器端 Web
应用程序将数据的标识和服务器上的动态数据元素合并在了一起,并将所构成的完整HTML文档返回给浏览器,违法了REST无状态服务器的原则,导致服务器
端必须保存大量会话状态,耗费服务器资源,削弱了应用程序的可伸缩性,并使得应用程序部署到集群环境更加困难,也使得分布式缓存变为不可能。
Ajax 应用程序在其主要 UI
和浏览器中的主要逻辑方面有所不同;基于浏览器的应用程序代码可以在必要时获取新的服务器数据,并将这些数据织入当前页面。呈现和数据绑定的位置看起来可
能是一个实现细节,但是这种区别会导致完全不同的架构风格。利用Ajax我们可以将用户状态信息保存在客户端,而非服务器,也就是说我们可以把ajax看
做是一种REST无状态原则的具体实现技术,通过REST与Ajax的结合,我们的web应用程序会更加完善。
利用有状态 Web 客户机的优点
人们通常将 Ajax
应用程序描述成无需在每次点击时彻底地刷新整页的Web页面。尽管这个描述非常确切,但是根本的动机在于彻底刷新整页会令用户不耐烦,从而无法获得愉快、
融入式的用户体验。从架构的角度来看,整个页面全部刷新的设计甚至非常危险,这种设计使您无法选择在客户机存储应用程序状态,这可能会导致妨碍应用程序充
分利用 Web 最强大的架构设计点的设计决策。Ajax
让我们不需要进行完全刷新就可以与服务器进行交互,这一事实使有状态客户机再次成为可用选择。这一点对于动态融入式 Web
应用程序架构的可能性有深远的影响:由于应用程序资源和数据资源的绑定转换到了客户端,因此这些应用程序都可以享受这两个世界中最好的东西 ——
融入式 Web 应用程序中动态、个性化的用户体验,以及遵守REST准则的应用程序中简单、可伸缩的架构。
缓存 Ajax 引擎
Ajax
引擎一个有趣的特征就是:尽管它包含了很多应用程序逻辑和表示框架元素,但是如果经过恰当的设计,它可以不包含任何业务数据或个性化内容。应用程序和表示
都冻结在部署时。在典型的Web 环境中,应用程序资源可能 6 个月才会变更一次。这意味着负责隔离应用程序资源和数据资源的 Ajax
引擎是高度可缓存的。
由于 Ajax 应用程序引擎只是一个文件,因此它也是可以使用代理缓存的。在大型的企业内部网中,只要有一名员工曾经下载过某个特定版本的应用程序的 Ajax 引擎,其他任何人都可以从内部网网关上上获取一个缓存过的拷贝。
因此对于应用程序资源来说,经过良好定义的 Ajax 应用程序引擎符合 REST 准则,与服务器端 Web 应用程序相比,它具有显著的可伸缩性优势。
缓存 Ajax 数据
用户浏览一个 Ajax Web 站点,加载 Ajax
应用程序引擎,最好是从浏览器缓存中加载的,否则就从本地代理服务器加载。那么对于业务数据来说情况如何呢?由于应用程序逻辑和状态都在浏览器上驻留并执
行,因此应用程序与服务器的交互就与传统 Web 应用程序的方式有很大的不同。不需要获取混合的内容页面,只需要获取业务数据即可。
现在我们考虑一下这个操作在(假想的)Ajax 版本的应用程序中的情况。对于 “最近查看的内容” 并不需要进行处理。当我们点击某个链接时,这些在页面上已经存在的信息并不会消失。有两个请求很可能会与设计模式的书籍有关:
- /Books/0201633612(其中 0201633612 是设计模式书的 ISBN 号)
- /PurchaseHistory/0201633612/bhiggins@us.ibm.com
第一个假定的请求会返回有关书籍的信息(作者、标题、简介等);其中并没有包含特定于用户的数据。非特定于用户的数据意味着当更多用户请求相同的资源时,
很可能会从 Internet
上的中间节点上来检索缓存版本,而不是从原始服务器上检索这些资源。这种特性会降低服务器和总体网络负载。另外一方面,第二个请求包含了特定于用户的信息
(Bill Higgins 的购买该书的历史记录)。由于这些数据包括一些个性化信息,因此只有一名用户需要从这个 URI
中获取并缓存数据。尽管这种个性化数据并没有非个性化数据的可伸缩特性,但是重要的问题是这些信息都是直接从 URL
中获取的,因此都具有这样的正面特征:它们都不会妨碍其他可缓存的应用程序和数据资源的缓存。
Ajax 和健壮性
Ajax 架构风格的另外一个优点是它可以轻松处理服务器的故障。正如我们前面介绍的一样,具有融入式用户体验的服务器端 Web
应用程序通常会在服务器上保存大量的用户会话状态。如果服务器发生了故障,会话状态就丢失了,那么用户就会体验到非常奇怪的浏览器行为(“为什么我又回到
主页上来了?我的购物车中的东西都到哪里去了?”)。在采用有状态客户机和无状态服务的 Ajax
应用程序中,服务器崩溃/重新启动对于用户来说都是完全透明的,因为服务器崩溃不会影响会话状态,这些都保存在用户的浏览器中;无状态服务的行为是幂等
的,可以由用户请求的内容来单独确定。
五、架构风格对比
目前基于网络应用的架构风格主要有三种:
RPC架构风格 将服务器看作是由一些过程组成,客户端调用这些过程来执行特定的任务。SOAP就是RPC风格的一种架构。过程是动词性的(做某件事),因此RPC建模是以动词为中心的。
分布式对象架构风格
认为服务器是由一些对象和对象上的方法组成,客户端通过调用这些对象上的方法来执行特定的任务。并且客户端调用这些对象上的方法应该就像是调用本地对象上
的方法一样,这样开发就可以完全按照统一的面向对象方法来做。但是很可惜,这样的抽象并不是很有效,因为分布式对象与本地对象存在着巨大的本质差别,想要
掩盖这些差别很多时候甚至是有害无益的。
REST架构风格 将服务器抽象为一组离散资源的集合。资源是一个抽象的概念,而不是代表某个具体的东西。注意:要真正理解REST,就一定要增强自己的抽象思维能力,充分理解到资源是抽象的。资源是名词性的,因此REST建模是以名词为中心的。
上述是目前基于网络的应用的主要的三种抽象方式。这三种不同的抽象方式会严重影响客户端与服务器的交互模式,而不同交互模式的交互效率差别相当大。分布式
对象的交互模式很多时候效率很低,因为掩盖了分布式对象与本地对象的差别,很多时候都会导致细粒度的API。实践已经证明,与RPC和分布式对象相
比,REST是一种对于服务器更加有效的抽象方式,将会带来粒度更大和更有效率的交互模式。这样的效果与Fielding设计REST的初衷是吻合
的,REST就是专门为交互的性能和可伸缩性进行过优化的一种架构风格。而SOAP在设计的时候优先考虑的从来不是性能和可伸缩性,而是互操作性,其开发
效率比较低。
REST的主要优势其实在于它是一种对于服务器的更加有效的抽象方式。
性能分析:与基于二进制通信的RPC例如RMI对比,REST是基于文本传输的,从这点看应该说性能不如前者,但是REST强调通信语义对于中间组件的可
见性,这样可以改善性能和可伸缩性。例如浏览器就是一种中间件。浏览器可以根据通信的语义来确定数据有没有发生改变,从而进行有效的缓存。RMI传输数据
再有效,它的数据也无法做有效的缓存。因此RMI的性能未必比REST好,况且不能缓存会带来严重的可伸缩性问题。
相关推荐
【REST开发小总结】 REST(Representational State Transfer,表述性状态转移)是一种网络应用程序的设计风格和开发方式,基于HTTP协议,以简洁明了的方式构建松散耦合的系统。REST的核心概念包括资源(Resource)...
### REST实战(REST in Practice)知识点总结 #### 一、REST简介与背景 - **REST (Representational State Transfer)**:一种软件架构风格,用于描述基于网络的应用程序如何工作。REST的核心理念是通过简单的HTTP...
REST(Representational State Transfer),即“表征...总结来说,REST是一种架构风格,它定义了一系列的约束条件,使得系统能够更好地适应Web的特性和环境。理解并正确应用这些约束条件是构建RESTful服务的关键所在。
REST 架构的关键点总结 - **非标准**: REST 不是一种标准化的协议,但它利用了现有的标准如 HTTP 和 URL。 - **资源导向**: REST 架构强调使用 URL 来标识资源,每个资源都有唯一的 URL。 - **无状态**: REST ...
`kafka-rest-proxy` 是一个重要的工具,它提供了一个RESTful接口来与Apache Kafka集群交互。这个工具使得非Java客户端可以方便地使用HTTP协议来生产和消费Kafka消息,无需直接集成Kafka的Java客户端库。以下是对`...
总结,WCF REST服务测试涉及到WCF服务的REST化设计、HTTP协议的理解以及客户端如何与服务进行有效通信。通过提供的“WCFRestServiceTest”项目,可以深入学习并实践这些概念,提升对RESTful服务开发的理解和应用能力...
总结来说,KEPWARE IoT Gateway 的 REST Server 提供了一种简单而灵活的方式,使开发者和系统管理员能够利用 RESTful API 与 KEPWARE 进行数据交互。通过配置网络设置、选择数据源、设置安全选项,以及使用 curl ...
总结来说,"geoserver-rest-python-1.1"是一个用于Python环境下的Geoserver REST API客户端,它提供了一种高效、易用的方式来管理Geoserver实例,优化后的1.1版本增强了其稳定性和功能,为地理信息系统开发提供了...
总结来说,Activiti REST服务是Activiti引擎与外部系统交互的重要桥梁,它使得流程管理更加灵活和便捷。开发者应当熟悉这些接口,以便在实际工作中高效地利用Activiti实现业务流程自动化。通过深入学习和实践,我们...
总结来说,REST是一种广泛应用于Web服务的架构风格,它通过定义资源模型、使用标准的HTTP方法和统一的接口,来实现系统的松耦合和可伸缩性。《REST实战中文版》作为深入研究REST的资料,将为读者提供详尽的理论知识...
总结,ArcGIS Server REST API是GIS开发的核心工具之一,理解并熟练运用它,能够极大地提升地理信息系统的开发能力和应用范围。通过深入学习和实践,开发者可以构建出高效、智能的GIS应用,满足各种业务需求。
总结起来,"Rest 开发小案例"是一个学习RESTful服务开发的好起点,它涵盖了使用Jersey框架创建REST服务的基础知识。通过此案例,开发者可以快速了解REST设计原则,掌握如何在Java环境中构建RESTful API,以及如何与...
总结起来,本例子通过Spring框架展示了如何开发一个简单的REST服务。从创建REST控制器、定义资源模型,到使用HTTP方法和JSON响应,以及如何测试和保护这些服务,这些都是开发REST API的基础步骤。理解并掌握这些概念...
#### 五、总结 本文介绍了如何使用Java语言调用HTTP REST接口,包括GET和POST两种常见的请求类型。通过示例代码,我们可以看到如何使用Apache HttpClient库来实现这些请求,并注意到一些重要的细节,比如异常处理和...
总结,Google Simple REST Client是一款强大的REST API测试工具,它的易用性和灵活性使得开发者能够高效地测试和调试REST服务。通过阅读提供的使用文档,可以更深入地了解其各种功能,并充分利用它来提升开发效率。
总结,使用Servlet实现REST框架涉及对HTTP方法的理解、URL映射、路径参数、内容协商以及业务逻辑的处理。这种实现方式简单直观,适合小型项目。然而,对于大型复杂的应用,更推荐使用Spring Boot或Vert.x等成熟的...
总结起来,REST和SOA是两种不同的服务架构设计,REST注重简洁和状态管理,适用于互联网场景,而SOA强调服务的重用和松耦合,适用于企业级应用。在实际应用中,两者并非相互排斥,而是可以相互融合,以适应不同场景的...
总结来说,"activiti-rest.zip" 提供了 Activiti 工作流引擎的 REST 接口实现,这对于希望以非侵入式方式集成 Activiti 到 Web 应用或微服务架构中的开发者来说是非常有价值的。通过理解和熟练使用这个 API,你可以...
总结来说,OceanStor V5系列的REST接口是其强大管理能力的重要体现,它简化了存储操作,提升了管理效率,并且能够无缝融入现代IT架构。通过理解和熟练运用这些REST API,无论是运维人员还是开发人员,都能够更好地...
总结来说,Salesforce REST API作为一项标准化的网络服务接口,允许开发者通过简单的HTTP请求来与Salesforce平台进行交互。它不仅在技术上易于集成和开发,而且功能强大,非常适合于移动应用和Web 2.0项目。开发者...