直至今日,分布式系统(Distributed System)已经取得了大规模的应用,特别是Web的发展,已经给软件开发带来了翻天覆地的变化,这一点已经毋庸置疑了。
构建分布式系统常用的技术通常就是使用分布式对象(DO),远程过程调用(RPC)方式。Web的架构为构建分布式系统带来了全新的开发方式,它抛弃了大量重量级、专家级的中间件,采用各种简单的中间件来满足企业级的需求,例如可靠性,安全,事务等。
REST架构
Web的基础架构就是REST架构,虽然Web开发从HTTP诞生那天起就应该是REST方式的,但是几乎所有当时的开发者都是使用传统的DO或者RPC去开发Web这个特殊的分布式系统。
REST是英文Representational State Transfer的缩写,中文翻译为“表述性状态转移”。它是由Roy Thomas Fielding博士在2000年首次提出的。在这篇论文中,博士为我们描绘了开发基于互联网的网络软件的蓝图。由于这篇论文学术性太强,导致它并未引起程序员们的注意。直到ROR(Ruby On Rails) 风行起来,它所宣扬的REST架构才真正的为人们所熟悉。但是ROR所提倡的只不过是使用HTTP协议完成简单的CRUD操作,离真正的REST架构还有很长一段路要走。在2008年的某次大会(不记得了)上,Fielding博士终于提出了真正的REST架构的核心思想:REST架构就是使用超媒体作为应用状态引擎(HATEOAS,即hypermedia as the engine of application state)。
REST核心
REST架构的核心理念就是使用HTTP作为应用协议操作网络资源,并且以超媒体(hypermedia)作为应用状态转移的载体。这里有以下几个重要的概念:
1. 资源
任何可以在网络上访问的数据都是资源,为了让其他的系统能访问这些资源,可以采用统一资源标识符(URI)来标识每一个资源。在Web开发中,最为常用的一种URI就是URL了。对于资源来说,由于每个系统对它的描述格式是不同的,这就导致同一个资源可能使用不同的表述方式,比如JSON格式,XML格式的。在REST架构中,资源的URL中一般不区分每种格式,格式交由Http Header去处理,比如application/json。
2. HTTP协议
REST架构使用HTTP作为应用协议去访问Web上的资源,而不是像传统的Web Service一样只是把HTTP当做一种传输协议。把HTTP当做应用协议体现为充分利用HTTP协议的消息来描述应用业务,体现为以下几点:
第一点,利用HTTP的Verb动词去描述应用的业务逻辑。比如:
GET 请求获取Request-URI所标识的资源,用于获取业务数据。 POST 在Request-URI所标识的资源后附加新的数据,用于创建业务数据。 PUT 请求服务器存储一个资源,并用Request-URI作为其标识,用于更新业务数据。 PATCH 如果说PUT是更新整个资源的话,PATCH可以只更新资源的一部分。 DELETE 请求服务器删除Request-URI所标识的资源,用于删除业务数据。 这几个是常用的完成CRUD操作的动词。其他的还有像: HEAD 请求获取由Request-URI所标识的资源的响应消息报头。 TRACE 请求服务器回送收到的请求信息,主要用于测试或诊断。 CONNECT 保留将来使用。 OPTIONS 请求查询服务器的性能,或者查询与资源相关的选项和需求。
具体的一个例子是,在业务逻辑中,我们有一个功能是获取一个员工的信息,在实现这个分布式应用的时候,我们就使用GET方法去访问指定的URI来申请员工的信息。这就是使用HTTP的动词去描述应用的业务。
第二点,使用HTTP的状态响应代码来描述业务逻辑的执行结果。
这一点不用多说,比如200来表示获取资源成功,201来表示资源创建成功,资源更新成功,404表示没有找到请求的资源,500表示服务器内部出错。
第三点,使用HTTP消息头的其他一些内容来辅助描述业务的数据和状态。
比如使用消息头中表示消息体类型的Content-Type,用于表示传输的数据新旧的Etag和Last-Modified,用于更新数据配合Etag使用的If-Match,用于缓存的Cache-Control,用于授权的Authorization等。
第四点,使用HTTP消息体中的超媒体表示应用程序的状态。
在老式的Web开发中,大家都使用URL隧道技术(来源于REST in Practice一书的称呼),其实就是把业务数据嵌入在了URL中,当做查询字符串处理,这在REST架构中是不能接受的。 严格的REST架构认为REST架构的先决条件就是使用超媒体作为应用程序的状态引擎。按我的理解,就是消息体存放的内容就是超媒体,它们描述了业务的当前状态和接下来可能的状态,根据这些描述,客户端就知道了业务接下来可能的操作。
比如在电子商务网站中,如果客户下了一个订单的话,客户会使用POST去创建一个订单,这个时候消息体包含的就是订单的一些数据,当服务端收到这个Request后,会在后端数据库中创建订单信息,然后会在Response的消息体中返回创建的订单的信息并包含接下来客户可以做的步骤,这些步骤通常就是一些超链接,比如使用GET获取订单的最新状态,使用DELETE删除该订单,或者使用POST创建付费申请资源等等。
3. 超媒体
其实超媒体并不是什么神秘的概念,超媒体只是超级媒体的缩写。超媒体是一种采用非线性网状结构对块状多媒体信息(包括文本、图像、视频等)进行组织和管理的技术。 超媒体在本质上和超文本是一样的,只不过超文本技术在诞生的初期管理的对象是纯文本,所以叫做超文本。随着多媒体技术的兴起和发展,超文本技术的管理对象从纯文本扩展到多媒体,为强调管理对象的变化,就产生了超媒体这个词。
连接各种媒体的形式就是超链接,所以超链接是超媒体的核心元素。在REST架构中,这个思路同样成立,消息体中的超媒体,核心的元素也就是超链接,各种形式表示的超链接;这些超链接可以被客户端很容易的就能解析,比如通常可以使用XHTML作为超媒体载体,因为XHTML有超链接元素,也可以使用Atom作为超媒体载体,因为Atom也有link元素。
使用超媒体后,程序的业务逻辑不再像是Web Service开发一样,是由WSDL描述的接口去限定了,而是全部由超媒体(超链接)去驱动。这样当Service做出一些修改后,只会反映到相应的链接中,不需要客户端做出任何的硬性修改(比如Web Service开发中接口的修改)。
REST成熟度模型
REST架构兴起以后,大家就需要给这些凌乱的认为实现了REST思想的网站评定是否满足REST的架构风格。认同比较多的就是Richardson的成熟度模型,Martin Fowler大师也这么谈论,如下图所示:
第0级(level 0)
这个级别的实现通常只有一个URI入口。应用程序也只是把HTTP作为一种普通的传输协议,在这之上构建应用层的协议实现远程Service的调用,这和CORBA,SOAP,POX(Plain Old XML)调用没有太多分别。
第1级(level 1)
这个级别的实现使用了大量的URI来描述各种不同的资源(Resource),同时把复杂的Service的分解为多个资源。但是实现应用的时候只使用单个的HTTP动词(通常是GET或POST)来完成所有的业务逻辑,业务逻辑的行进方向完全隐藏在URI中(查询字符串中的参数),大多数现行的网站都属于这个级别。
第2级(level 2)
在第一级的基础之上,这个级别引入HTTP标准的动词词汇,用于加强客户端和资源URI的交互的语义性。比如使用POST/GET/PUT/DELETE完成常见的CRUD操作。在使用标准语义操作词汇的同时,还运用HTTP的标准的CODE代码来表达交互操作的结果。例如200/201/400等表达不同的交互操作结果。一些设计良好的网站属于这个级别,比如亚马逊S3服务,基于ROR创建的许多服务。
第3级(level 3)
在第二级的基础之上,这个级别加强了状态转换的表达,加强了状态切换的可发现性。这个级别实现了HATEOAS(Hypertext As The Engine of Application State)的机制,在每一个服务器端返回给客户端的消息体中加上一些可以帮助客户端了解和指导可能存在的link,从而按照不同的link实现不同的状态的迁移。这就好比给客户端程序就像一个使用浏览器的人一样,资源的Representation就好比展现在浏览器中的HTML一样。浏览的人可以通过HTML中的link实现不同页面的浏览。通过HATEOAS,准确的来说只需要对外广告资源的入口,就可以完成所有资源状态之间的切换和导航。
Web Service安魂曲?(源于REST in Practice一书的称呼)
目前来看,答案应该是否定的。我个人觉得原因有下列几点:
首先,很多开发人员已经熟悉了Web Service的开发方式,即使REST相比而言优势更明显,但是由于很多人比较懒,都倾向于采用成熟的技术,内心一般也抵制新的技术(当然很多人还是热衷于新技术的),所以Web Service开发还会持续较长一段时间。
其次,很多Web Service开发人员都是专家级的人物,转向新技术的话其优势将损失殆尽。
最后,Web Service开发的标准WS-*日趋完善,功能日益强大,而且针对很多的内部平台,WS开发仍然具有强大的吸引力。
总的来说,Web Service与REST开发应该不是严格的替代关系,它们会长久的并存并向前发展,就如同REST架构也不会替代MVC开发一样,因为它们都有各自最擅长的场景。