`
empireghost
  • 浏览: 52412 次
  • 来自: ...
社区版块
存档分类
最新评论
阅读更多

REST的基本思想。[Fielding]把REST形式化地定义为一种架构风格(architecture style),它有架构元素(element)和架构约束(constraint)组成。这些概念比较晦涩难懂,而且我们做工程的往往并不需要形而上的理 解。我们只知道,REST是一种针对网络应用的设计和开发方式,可以降低开发的复杂性,提高系统的可伸缩性。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有这样的好处,那我们应该义无反顾地拥抱它啊!目前一些大牛(像DHH)都已经开始投入到了REST的世界,那我们这些人应该做什么或者说思考写什么你呢?我觉得我们应该思考两个问题:

  1. 如何使用REST;
  2. 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动作是一个资源。

现在,我们来复杂一些的东东。如何用url表达“category为ruby 的article”?一开始可能想到的是/category/ruby/articles,这种想法很直观。但是我觉得里面的category是不需要 的,我们可以直接把“/ruby”理解为“category是ruby”,也就是说“ruby”出现的位置说明了它指的就是category。OK, /ruby/articles,单单从这个url上看,我们能获得多少关于category的信息呢?显然category隐藏在了url后面,这样做到 底好不好,应该是仁者见仁,智者见智了。对于如何表达category这样的东西,我还没想出很好的方式,大家有什么好idea,可以一起讨论。

另 外还有一种url形式,它对应到程序中的继承关系。比如product是一个父类,book和computer是其子类。那么所有产品的url应该是 /products,所有书籍的url应该是/books,所有电脑的url应该是/computers。这一想法就比较直观了,而且再次验证了url可 以帮助我们进行设计的论点。

让我再说明一下我的想法:如果每个用户需求都可以抽象为资源,那么就可以完全使用REST。

由此看来,使用REST的关键是如何抽象资源,抽象得越精确,对REST的应用就越好。因此,如何改变我们目前根深蒂固的基于action的思想是最重要的。

有 了对第一个问题的讨论,第二个问题就容易讨论多了。REST会取代MVC吗?还是彼此是互补关系(就像AOP对于OOP)?答案是It depends!如果我们可以把所有的用户需求都可以抽象为资源,那么MVC就可以推出历史的舞台了。如果情况相反,那么我们就需要混合使用REST和 MVC。

当然,这是非常理想的论断。可能我们无法找到一种方法可以把所有的用户需求都抽象为资源,因为保证这种抽象的完整性(即真的是所 有需求都可以)需要形式化的证明。而且即使被证明出来了,由于开发人员的能力和喜好不同,MVC肯定也会成为不少人的首选。但是对于希望拥抱REST的人 来说,这些都没有关系。只要你开发的系统所设计的问题域可以被合理地抽象为资源,那么REST就会成为你的开发利器。

所以,所有希望拥抱REST的朋友们,赶快训练自己如何带上资源的眼镜看世界吧,这才是REST的核心所在。

分享到:
评论
1 楼 ScorpioX 2009-07-08  
关于REST,有一点非常重要:REST的限制条件(Constraints),例如
  • 通过URI来给所有的资源加上ID
  • 通过资源的Representation对资源进行操作
  • 统一的接口,如(GET, POST, PUT, DELETE)
  • 消息可以自描述


其中最重要的一条:用超文本来实现应用状态的转移(Hypermedia as the engine of application state, HATEOAS)————前面的那几条都好说,如果不满足这一条,其实不能称为是一个REST的系统。

很多号称提供REST API的系统(例如Flickr),其本质其实是XMLPRC over HTTP。例如,Flickr的API可能会返回一堆图片的ID,然后客户端自己拼装一个图片的URI去取图片——听起来很简单吧。就像我知道了一个帖子的编号,直接用/posts/12345去取,多好啊?可这种方案的问题是,服务器无形中背上了一个沉重的负担——必须永久性地支持/posts/{id}这种URL的Pattern,一旦需要做调整,例如加入用户ID:/{user_id}/posts/{id}或者数据迁移到其他服务器上,例如http://another_server/posts/{id},问题就来了——老的Pattern /posts/{id}要不要支持?怎么支持?

真正的REST方式:服务器明确地给出每个帖子的URI而不是简单的{id},例如/posts可以返回一堆URL(Pattern)完全不同的帖子,而客户端都可以正确地访问。

总之,遵循HATEOAS限制条件的好处在于,减小客户端对服务器端资源结构及实现细节的假定,即降低所谓的带外知识,也就是减小客户端与服务器端的耦合度——虽然这种好处很不直观。引用一个比较形象的说法:HATEOAS就像是服务器依次丢出一个一个的米粒,引导吃米的小鸡(用户)到达他想去的目的地。如果下次小鸡直奔上次的目的地,那里可能已经搬迁了。


感觉其实现在有很多对REST的误解,个人想法:
  • REST并不简单(虽然URL看起来简单)——其思想体现了很高深的智慧
  • REST系统运行效率不高,其实RPC相对很高效(但需要很多带外知识)
  • REST不是万能的,不是所有的事情都适合抽象成资源——想象一下用REST实现一个钢琴
  • ...


采用REST有利也有弊,对任何一种技术或架构,都不能盲目狂热地崇拜,冷静分析用心思考才能找到最适合的解决方案。

相关推荐

    REST Server in Delphi XE Using DataSnap中文版

    ### REST Server 在 Delphi XE 中使用 DataSnap 的关键技术点 #### 1. REST 架构简介 - **背景**: REST(Representational State Transfer)是 Web 服务领域的一个重要概念,尤其在过去十年中,随着 Web 2.0 的...

    谷歌浏览器插件+AdvancedRestClient+Http Rest API测试调试

    1. 安装Advanced REST Client插件:首先,你需要在Chrome浏览器的Web Store中搜索“Advanced REST Client”并安装它。安装完成后,你可以在浏览器的扩展程序栏找到ARC的图标。 2. 创建新的HTTP请求:打开ARC,点击...

    REST地图与天地图叠加

    本示例探讨的主题是“REST地图与天地图叠加”,这涉及到两种不同的地图服务技术的融合,即SuperMap iClient的REST地图服务和天地图服务。我们将详细解释这两种技术及其在Flex客户端下的叠加应用。 首先,REST...

    Rest Severs in Delphi XE Using DataSnap

    在Delphi XE中利用DataSnap构建REST服务器是一项强大的技术,可以帮助开发者创建高效、可扩展的Web服务。本文将深入探讨这一主题,介绍REST(Representational State Transfer)架构原理,以及如何在Delphi环境中...

    REST服务构建的web应用的优势和不足

    REST 服务构建的 Web 应用优势和不足 REST(REpresentational State Transfer)是一种混合架构风格,当前互联网的核心架构风格。基于 REST 服务(RESTful Service)的 Web 应用系统设计任务主要包括:识别并设计 ...

    Kepware IOT gateway使用教程 - REST Sever

    其中,REST Server 模块是实现这一目标的关键组件,它提供了基于 RESTful API 的接口,使得应用程序能够轻松地从 KEPWARE 获取或写入数据。本教程将详细介绍如何在 KEPWARE 中配置和使用 REST Server。 首先,确保...

    geoserver-rest-python-1.1

    【标题】"geoserver-rest-python-1.1" 是一个针对Geoserver的REST API接口的Python客户端库,主要用于管理、配置和操作Geoserver的版本1.1。这个库是Geoserver-rest-python-1.0的升级版,修复了已知的错误并进行了...

    elasticsearch-rest-high-level-client-6.8.3-API文档-中英对照版.zip

    赠送jar包:elasticsearch-rest-high-level-client-6.8.3.jar; 赠送原API文档:elasticsearch-rest-high-level-client-6.8.3-javadoc.jar; 赠送源代码:elasticsearch-rest-high-level-client-6.8.3-sources.jar;...

    REST实战(REST in Practice)

    ### REST实战(REST in Practice)知识点总结 #### 一、REST简介与背景 - **REST (Representational State Transfer)**:一种软件架构风格,用于描述基于网络的应用程序如何工作。REST的核心理念是通过简单的HTTP...

    elasticsearch-rest-client-6.8.3-API文档-中文版.zip

    赠送jar包:elasticsearch-rest-client-6.8.3.jar; 赠送原API文档:elasticsearch-rest-client-6.8.3-javadoc.jar; 赠送源代码:elasticsearch-rest-client-6.8.3-sources.jar; 赠送Maven依赖信息文件:elastic...

    elasticsearch-rest-high-level-client-6.8.3-API文档-中文版.zip

    赠送jar包:elasticsearch-rest-high-level-client-6.8.3.jar; 赠送原API文档:elasticsearch-rest-high-level-client-6.8.3-javadoc.jar; 赠送源代码:elasticsearch-rest-high-level-client-6.8.3-sources.jar;...

    C# 实现Rest服务接口,含实现文档

    本项目“C# 实现Rest服务接口,含实现文档”将详细介绍如何使用C#和ASP.NET框架来构建RESTful服务。 1. **C#语言基础**:C#是Microsoft开发的一种面向对象的编程语言,常用于Windows平台的应用程序开发,尤其在.NET...

    动态发布rest接口及服务调用

    在IT行业中,REST(Representational State Transfer)是一种广泛应用于网络应用程序设计的架构风格,它强调资源的表述状态转移。REST接口通常使用HTTP协议中的方法(GET、POST、PUT、DELETE等)来操作资源,实现轻...

    kettle rest 接口 请求实例

    在Kettle中,REST接口提供了一种灵活的方式与外部系统进行通信,例如,发送和接收JSON数据,执行各种操作。本教程将深入探讨如何使用Kettle与RESTful服务进行交互。 首先,我们要理解REST(Representational State ...

    JavaScript天地图叠加REST地图服务

    JavaScript天地图叠加REST地图服务是将SuperMap iClient 6R for JavaScript库与天地图的REST服务相结合,实现在线地图的动态加载与显示。在Web应用中,这种技术常用于地理信息系统(GIS)的开发,使得用户可以在...

    Asp.net 实现 Rest服务接口

    【Asp.net 实现 Rest服务接口】 在现代Web开发中,REST(Representational State Transfer,表述性状态转移)已经成为一种广泛采用的API设计风格。它基于HTTP协议,以简洁、可扩展的方式提供服务,便于客户端与...

    JIRA REST Java Client

    **JIRA REST Java Client**是Atlassian官方提供的一款用于与JIRA进行交互的Java库,它使得开发人员能够轻松地通过RESTful API访问和操作JIRA系统。这个库提供了丰富的功能,包括创建、更新、查询问题(issues)、...

    Java 调用Http Rest接口 例子说明

    REST (Representational State Transfer) 是一种设计网络应用程序的架构风格,其核心原则之一是无状态性。在REST架构中,客户端和服务端之间的交互基于HTTP协议,通过发送HTTP请求并接收HTTP响应来完成。 #### 三、...

    elasticsearch-rest-client-6.3.0-API文档-中英对照版.zip

    赠送jar包:elasticsearch-rest-client-6.3.0.jar; 赠送原API文档:elasticsearch-rest-client-6.3.0-javadoc.jar; 赠送源代码:elasticsearch-rest-client-6.3.0-sources.jar; 赠送Maven依赖信息文件:elastic...

Global site tag (gtag.js) - Google Analytics