写点什么

在 RESTful 应用程序中的超媒体

  • 2008-03-20
  • 本文字数:4656 字

    阅读完需:约 15 分钟

超媒体到底是什么?!

如果你有幸听说过 REST 架构风格,那么你也可能听说某些人认为统一接口是最重要的约束,尤其是该接口在制约资源上能被调用的方法方面。但是,你没有意识到的是,对于统一接口还有很多东西。特别是一个被笨拙地冠以“超媒体即应用状态引擎(hypermedia as the engine of application state)”名字的子约束,它可以认为是 REST 最重要的约束,在某种意义上它独力塑造了我们所熟知的 RESTful 系统的大部分的“形状”。

本文中我们将深入讨论这个约束,试图去搞清楚它的含义和理解它的价值。

定义

不幸的是, REST 论文没有在这个约束上展开,除了它的名字和对它实际应用的描述:

所以,模型应用是一个从一个状态迁移到下一个状态的引擎,迁移是通过对当前表述性集合中可选状态进行检查和选择而完成的。

尽管它给我们提供了一个有用的描述,但是在我看来,它不能帮助我们真正理解约束本身的作用域;约束真正允许的是什么,不允许的又是什么。由此开始,接下来还值得注意的是我们能从约束自身名字中获取些什么信息。

“应用状态”指的是一个状态,它决定了用户在完成一个任务的流程中所处的“位置”。例如,在做个人银行业务的时候,用户是正在浏览帐户余额,还是在填写账目付款单,或者是在订购新的支票?它们每个都是不同的应用状态。有些人错误地认为“状态”是指资源状态,在上面例子里,资源是指帐户余额或者近期付款清单。但“应用状态”和“资源状态”是不同的。

应用状态也被称为“会话状态”,该状态也是 REST 的“无状态”约束所指的状态,这种约束要求客户端独自维持状态。反之,如果你使用诸如 VNC 或者 Windows 远程桌面的远程会话技术,那么应用状态完全保存在服务器上。

Ted Nelson 在 1962 年创造了“超媒体”一词,是他发明的“超文本”泛化。鉴于超文本产生了内部互联的文本文档,那么超媒体将范围扩展到了任何形式的媒体。当然,两者的关键点都是我们可以在使用的内容嵌入链接。

约束实战

REST 在 2003/2004 年开始获得一些从事面向互联网服务开发者的关注——至少这些开发者确实将他们的服务冠以“REST”的绰号——最明显的是两个高调、自我标榜的“REST API”: Flickr Amazon 。有趣的是两个服务也同时提供了基于 SOAP 的接口,但是与“REST API”相比,这两个 SOAP API都没有显出更多的使用。最终,REST 社区拥抱了这些服务,并且将它们作为一种进一步解释在Web 上使用REST 风格的价值和魅力的工具。不幸的是,这些API 存在一个问题:它们不完全是RESTful 的,因为它们无视(至少)一个REST 约束。事实上,Flickr API(以及Amazon、del.icio.us 等等)的问题比我们在此讨论的要多得多,此处我们只关注那些和超媒体有关系的问题。

幸运的是,我们不需要为寻找这些问题花太多时间。以“flickr.contacts.getList”操作返回的样本数据为例,用户可使用该操作获得他们自己的联系人清单:

<contacts page="1" pages="1" perpage="1000" total="3"><br></br> <contact nsid="12037949629@N01" username="Eric" iconserver="1"<br></br> realname="Eric Costello"<br></br> friend="1" family="0" ignored="1" /><br></br> <contact nsid="12037949631@N01" username="neb" iconserver="1"<br></br> realname="Ben Cerveny"<br></br> friend="0" family="0" ignored="0" /><br></br> <contact nsid="41578656547@N01" username="cal_abc" iconserver="1"<br></br> realname="Cal Henderson"<br></br> friend="1" family="1" ignored="0" /><br></br></contacts>这里,“nsid”属性包含了一个表示单个联系人的唯一标识符,在这个例子里是其中的三个联系人。但是一旦客户端已经检索到了这个文档,接下来会怎样?如果他们想了解更多关于 Cal Henderson 的信息怎么办?通过快速检查 Flickr API 文档,可以发现有一个叫做"flickr.people.getInfo"的操作,它接收nsid 作为一个参数,返回那个nsid 字符串所标识联系人的更多信息。那么为了获得关于Cal 的更多信息,我们在HTTP GET 消息中需要使用的URI 将是:

http://api.flickr.com/services/rest/?method=flickr.people.getInfo?auth_key=xxxx&user_id=41578656547@N01这不是超媒体。一个超媒体解决方案会使用标准化的标识符——对于 Web 来说就是 URI——而非私有的标识符,这避免了客户端在从联系人清单文档浏览到个人信息文档过程中需要特定于 Flickr 的知识。如果采用标准标识符,那么第一个文档应该是:

<contacts page="1" pages="1" perpage="1000" total="3"><br></br> <contact nsid="http://api.flickr.com/services/rest/?method=flickr.people.getInfo?auth_key=xxxx&user_id=12037949629@N01" username="Eric" iconserver="1"<br></br> realname="Eric Costello"<br></br> friend="1" family="0" ignored="1" /><br></br> <contact nsid="http://api.flickr.com/services/rest/?method=flickr.people.getInfo?auth_key=xxxx&user_id=12037949631@N01" username="neb" iconserver="1"<br></br> realname="Ben Cerveny"<br></br> friend="0" family="0" ignored="0" /><br></br> <contact nsid="http://api.flickr.com/services/rest/?method=flickr.people.getInfo?auth_key=xxxx&user_id=41578656547@N01" username="cal_abc" iconserver="1"<br></br> realname="Cal Henderson"<br></br> friend="1" family="1" ignored="0" /><br></br></contacts>万事大吉,但是把这些变到超媒体对他们和他们的用户会有什么好处呢?

为了从一个应用状态前进到另一个应用状态,以 Flickr 现在的方式,要求客户端处理特定于 Flickr 的知识,这是另一种形式的私有应用。它不仅是私有的,而且即使在 Flickr API 本身内部它也不是一个一致的模型,因为从联系人清单文档浏览到联系人个人信息文档所需要的知识(如上面所述),不同于从联系人个人信息文档浏览到联系人个人照片清单所需要的知识(它是“flickr.photos.getContactsPublicPhotos”)。这给Flickr 提出了可发展性问题,因为即使对API 进行简单地扩展也轻易地要求传播新知识,需要依次修改客户端代码。一个诸如搜索引擎这样的普通客户端,也不能通过这些API 来给Flickr 内容建立索引,因为我确信搜索引擎的维护人员——或者其他使用这个应用程序模型的人——对于每次Ficlkr 扩展API 都需升级他们的软件不会有太多的兴趣。再次重申,这不仅仅限于超媒体:任何标准化的应用模型都会提供同样的好处。当然,超媒体模型已经证明它自己非常流行,即使那些使用它的人们没有意识到自己所做的事。

因此通过使用一个公共应用模型,它不仅仅是标准化的,而且总是稳定的,你可以通过准许消费者和生产者独立进化来降低两者间耦合。通过这种方法,新旧服务可以被组合在一起形成一个组合应用,新老客户端也可以合并成一个。我认为,一旦Web 可以让人们简单地在一个文档中包含一个指向几年前创作的页面和该内容消费者,当我们使用它时,完全可以无缝地浏览内容而无须下载一个新版本的浏览器。这都是特意设计的,决非偶然。

值得注意的是,Web 决没有垄断超媒体的使用。Email 是另一个已普及的应用,我们大家在互联网上每天都用到它,也是如此。每条Email 消息包含携带发信人和收信人的Email 地址的头,而拥有这些地址中的一个或者多个就足够发送另一条Email 消息了。

当我们在讨论这些鲜为人知的事实时,你可能也会有兴趣知道:Web 本身一个重要方面使用超媒体: robots.txt ,亦称漫游器排除文档(robot exclusion)。它的工作方式:如果网站希望搜索引擎不要给它们的某些内容建立索引,那么就在他们的“/robots.txt” URI 中简单地放置一个文件,该文件描述了哪些内容不希望被建立索引。但是,就我所知的是“几乎没有人链接到robots.txt 文件”。为什么会这样?“/robots.txt”是一个固定且众所周知的位置,特别是对于搜索引擎来说:给出任何URI,它们都能从URI 构建出这个站点域相应的robots.txt URI。尽管这不是超媒体,因为链接不是动态地从另一个页面发现的,搜索引擎恰恰认为这是一个优点。这不能说它是一个的解决方案,因为超媒体方式需要两次网络往返(一次是发现链接robots.txt 的页面,另一次是抓取页面),这对于所有的当事方都是一种负担。所以这也是一个关于超媒体成本的好例子。但是要牢记这点:只有在极少情况下这(译注:即不采用超媒体)真的才是最佳方式。和robots.txt 原因相同,站点地图可能也算一个;但是其他的诸如“favicon.ico”和Apple 新的 iPhone WebClip 特性,将可能从使用超媒体上获益;例如,那些图标可以被一个图像搜索引擎搜索到,而不需要更新搜索引擎软件。

在考虑超媒体时,另一个值得关注的技术是 WADL ,Web 应用描述语言。尽管它自称“RESTful 描述语言”,但是对它有一个重要的警告。考虑从这个从 WADL 文件中摘录的例子:

<resources base="http://service.example.com/myservices/"><br></br> <resource path="search"><br></br> <method name="GET" id="search"><br></br> <request><br></br> <param name="query" type="xsd:string" style="query" required="true"/><br></br> </request><br></br> <response><br></br> <representation mediaType="application/xml" element="yn:ResultSet"/><br></br> <fault status="400" mediaType="application/xml" element="ya:Error"/><br></br> </response><br></br> </method><br></br> </resource><br></br></resources>这个文件将一个“search”资源声明为一个“myservices”集合的一部分。通过声明使用 HTTP GET 和使用“query”参数,它描述了客户端从它选择的输入字符串构建一个 URI 的方式。

表面上看,它似乎是一个完美 RESTful 的、基于超媒体的解决方案,非常类似 HTML 表单(或者 URI 模板)的使用方式。那么警告是什么?问题在于 WADL 被消费的时机。某些对基于 Web 的解决方案感兴趣的 Web 服务支持者按照他们使用 WSDL 的方式(作为设计时部件)使用 WADL。但是,这样使用 WADL,类似于在编译浏览器的时候,开发一个具有内建知识(比方说 Google 主页表单)的 Web 浏览器:如果在部署浏览器后,Google 以不向后兼容的方式改变了这个表单(即,不仅仅增加一个新的可选参数),那么浏览器将无法使用那些资源 / 服务。使用具有 WADL 的超媒体约束意味着客户端应该在运行时消费 WADL。所以小心地选择你的 WADL 工具,因为那些试图帮助你的一些工具,可能帮倒忙。

结论

希望超媒体约束的价值现在看起来要明显多了。但是,不仅仅如此,我真正希望的是:当你决定使用它时,你能更好地了解哪些实践是你应该避免的。

记住:超媒体只是统一接口约束中的一员,因此对于后者更通用石蕊测试是:如果你正在开发客户端代码,而客户端代码假定它不能适用于所有资源(或者服务端“API”需要客户端的this,译注:服务端需要客户端的信息),那么你就没有使用统一接口。

关于作者

Mark Baker 在 SOA 和 Web 服务社区大名鼎鼎,源于他对推广 REST(表述性状态转移)架构风格的不断努力,以及他批评大多数标准和规范不了解什么成就并持续成就了 Web 的成功。

查看英文原文 Hypermedia in RESTful applications - - - - - -

译者简介:王志雄,长期从事软件开发工作,项目集中在 EAM 和设备点检管理领域。2004 年转入 JAVA 领域,曾经在项目中使用过 Hibernate、Struts、Spring 等。关心软件技术和相关工具的动态,将其中成熟的技术和工具应用到实际的项目之中。关心开源软件的发展动态以及软件过程和敏捷开发的实践探索。

2008-03-20 04:484099

评论

发布
暂无评论
发现更多内容

QSpace Pro for Mac(多窗文件管理器)

展初云

文件管理 Mac软件

代码的艺术 - Writing Code Like a Pianist | 京东云技术团队

京东科技开发者

代码质量 整洁代码 企业号10月PK榜 系统质量

原料所属权管理领先实践,助力造币厂来料加工原料管理降本增效

用友BIP

领先实践 原料所属权管理

新晋技术管理者如何推动组织变革?

LigaAI

团队管理 研发管理 进阶 技术管理 企业号10月PK榜

从理论到实践,实时湖仓功能架构设计与落地实战

袋鼠云数栈

数据中台 数据仓库 数据湖 湖仓一体 实时湖仓

以烟草行业为例,聊聊如何基于 PLC + OPC + TDengine,快速搭建工业生产监测系统

TDengine

tdengine 时序数据库

推动产业升级及创新,Doris Summit Asia 2023 先进智造与电信论坛提前揭秘

SelectDB

数据库 大数据 数据仓库 实时数仓 apache doris

九章云极DataCanvas多模态大模型平台实践与思考

九章云极DataCanvas

黄金眼PAAS化数据服务DIFF测试工具的建设实践 | 京东云技术团队

京东科技开发者

测试 PaaS 回归测试 企业号10月PK榜

面试多起来了

王磊

Java

最全数据安全评估标准汇编,你应该需要!(附下载)

极盾科技

数据安全

英语学习工具:Eudic欧路词典 for Mac增强版

展初云

Mac 欧路词典 英语学习工具

使用 ChaosBlade 验证 DLRover 的弹性和容错的稳定性

AI Infra

人工智能 开源 开发者 云原生 大模型

全面解析内存泄漏检测与修复技术

华为云开发者联盟

程序员 开发 内存 华为云 华为云开发者联盟

PaddleX解决分类、检测两大场景问题?实战精讲教程来了!

飞桨PaddlePaddle

AI 飞桨 套件

架构师日记-聊聊开发必掌握的那些实践技能 | 京东云技术团队

京东科技开发者

软件开发 代码注释 开发技能 企业号10月PK榜

用友 Fast by BIP引领专业技术服务企业快速迈向数智化创新

用友BIP

Fast by BIP

使用流量管理工具保护 Kubernetes 的六种方法

NGINX开源社区

Kubernetes DOS攻击 Web应用防火墙 原生云

百度世界大会2023重磅发布进行时,小度全新智能音箱重构家居美学新乐章

新消费日报

李彦宏:我们即将进入一个AI原生的时代|百度世界2023

飞桨PaddlePaddle

百度 大模型 文心一言

SOA认知和方法论 | 京东物流技术团队

京东科技开发者

架构 软件架构 SOA 企业号10月PK榜

低代码平台探讨-MetaStore元数据缓存 | 京东云技术团队

京东科技开发者

缓存 低代码 元数据 企业号10月PK榜

AIGC立法和相关版权案例分享-“心寄源”法律沙龙(2023第五期 | 总第十期)成功召开

开放原子开源基金会

如何从构建到运营?数科公司数智创新研讨会成功举办

用友BIP

数科公司

SoundSource for mac(音量控制工具)

展初云

Mac软件 音量调节

玩转MaxCompute SQL训练营! 数据分析挖掘迅速出师

阿里云大数据AI技术

大数据 数据分析

LAS Spark+云原生:数据分析全新解决方案

字节跳动数据平台

数据库 大数据 数据中台 数据研发 企业号10月PK榜

校源行 | 开放原子开源社团(西北工业大学)授牌仪式成功举行

开放原子开源基金会

商用显示设备包括哪些?

Dylan

企业 设备 显示器 LED显示屏

图文结合丨Prometheus+Grafana+GreatSQL性能监控系统搭建指南(下)

GreatSQL

greatsql

欢迎来到 GPTSecurity!共建知识库

云起无垠

GPTSecurity

在RESTful应用程序中的超媒体_SOA_Mark Baker_InfoQ精选文章