1.4 RESTful
REST(Representational State Transfer,表述性状态转移)是一种软件架构风格、设计风格,而不是标准,它只是提供了一组设计原则和约束条件,主要用于客户端和服务器端交互类的软件。基于这个风格设计的软件可以更简洁、更有层次、更易于实现缓存等机制,其实现的位置如图1-6所示。
图1-6 REST位置示意图
1.4.1 概述
REST描述了一个架构样式的网络系统,例如,Web应用程序首次出现在2000年Roy Fielding(HTTP规范的主要编写者之一)的博士论文中。在目前主流的三种Web服务交互方案中,REST相比于SOAP(Simple Object Access Protocol,简单对象访问协议)以及XML-RPC(XML Remote Procedure Call,XML远程过程调用)更加简单明了,无论是对URL(Uniform Resource Locator,统一资源定位符)的处理,还是对载荷的编码,REST都倾向于用更加简单的方法设计和实现。值得注意的是,REST并没有一个明确的标准,而更像是一种设计的风格,交互风格如图1-7所示。
REST指的是一组架构约束条件和原则,满足这些约束条件和原则的应用程序或设计就是RESTful。
图1-7 REST交互风格
Web应用程序最重要的REST原则是,客户端和服务器端之间的交互请求是无状态的。从客户端到服务器端的每个请求都必须包含理解请求所必需的信息。如果服务器端请求在任何时间点重启,客户端不会得到通知。此外,无状态请求可以由任何可用服务器端回答,这十分适合云计算之类的环境,客户端可以缓存数据以改进性能。
在服务器端,应用程序状态和功能可以分为各种资源。资源是一个有趣的概念实体,它向客户端公开。资源是应用程序对象、数据库记录、算法等。每个资源都使用URI(Universal Resource Identifier,统一资源标识符)得到一个唯一的地址。所有资源都共享统一的接口,以便在客户端和服务器端之间传输状态。它使用的是标准的HTTP方法,如GET、PUT、POST和DELETE。超媒体是应用程序状态的引擎,资源表示通过超链接互联。
另一个重要的REST原则是分层系统,也就是说,无法了解与之交互的中间层以外的组件。通过将系统知识限制在单个层,可以限制整个系统的复杂性,促进了底层的独立性。
当REST架构的约束条件作为一个整体应用时,将生成一个可以扩展到大量客户端的应用程序。它还降低了客户端和服务器端之间的交互延迟。统一界面简化了整个系统架构,改进了子系统之间交互的可见性,REST简化了客户端和服务器端的实现。
1.4.2 实现
了解了什么是REST,下面介绍RESTful的具体实现。本节主要描述RESTful Web服务与RPC样式的Web服务的区别、RESTful Web服务的Java框架、构建RESTful Web服务的多层架构。
1. RESTful Web服务与RPC样式的Web服务的区别
使用RPC样式构建基于SOAP的应用,成为实现面向服务架构的最常用方法。RPC样式的Web客户端将一个装满数据的数据包(包括方法和参数信息)通过HTTP发送到服务器端。服务器端打开数据包,使用传入参数执行指定的方法,将结果打包作为响应发回客户端,客户端收到响应并打开数据包,每个对象都有自己独特的方法以及仅公开一个URI的RPC样式Web服务,URI表示单个端点。这种方法忽略HTTP的大部分特性且仅支持POST方法。
由于轻量级以及通过HTTP直接传输数据的特性,Web服务的RESTful方法已经成为最常见的替代方法。可以使用各种语言(如Java、Perl、Ruby、Python、PHP、JavaScript和Ajax)实现客户端。RESTful Web服务通常可以通过自动客户端或代表用户的应用程序访问。但是,这种服务的简便性让用户能够与之直接交互,使用它们的Web浏览器构建一个GET URL并读取返回的内容。
在RESTful样式的Web服务中,每个资源都有一个地址。资源本身都是方法调用的目标,方法列表对于所有资源都是标准方法,包括HTTP的GET、POST、PUT和DELETE,还可能包括HEADER和OPTIONS。
在RPC样式的架构中,关注点在于方法;而在RESTful样式的架构中,关注点在于资源,它将使用标准方法检索并操作信息字段(使用表示的形式),资源表示使用超链接形式。
Leonard Richardson和Sam Ruby在他们的著作RESTful Web Services中引入了术语RESTRPC混合架构。REST-RPC混合Web服务不使用打包封装方法、参数和数据,而是直接通过HTTP传输数据,这与RESTful样式的Web服务是类似的。但是它不使用标准的HTTP方法操作资源,它在HTTP请求的URI部分存储方法信息。知名的Web服务(如Yahoo的Flickr API和Delicious API)都使用这种混合架构。
2. RESTful Web服务的Java框架
有两个Java框架可以帮助构建RESTful Web服务。Erome Louvel和Dave Pawson开发的Restlet是轻量级的。它实现针对各种RESTful系统的资源、表示、连接器和媒体类型之类的概念,包括Web服务。在Restlet框架中,客户端和服务器端都是组件。组件通过连接器互相通信。该框架最重要的类是抽象类Uniform及其具体的子类Restlet,Uniform的子类是专用类,如Application、Filter、Finder、Router和Route。这些子类能够一起处理验证、过滤、安全、数据转换以及将传入请求路由到相应资源等操作。Resource类生成客户端的表示形式。
JSR-311是Sun Microsystems的规范,可以为开发RESTful Web服务定义一组Java API。Jersey是对JSR-311的参考实现。JSR-311提供一组注解,相关类和接口都可以用来将Java对象作为Web资源展示。该规范假定HTTP是底层网络协议,它使用注释提供URI和相应资源类之间的清晰映射,以及HTTP方法与Java对象方法之间的映射。API支持广泛的HTTP实体内容类型,包括HTML、XML、JSON、GIF和JPG等。它还将提供所需的插件功能,以允许使用标准方法,通过应用程序添加其他类型。
3. 构建RESTful Web服务的多层架构
RESTful Web服务和动态Web应用程序在许多方面都是类似的。有时它们提供相同或非常类似的数据和函数,尽管客户端的种类不同。例如,在线电子商务分类网站为用户提供一个浏览器界面,用于搜索、查看和订购产品。如果为公司、零售商甚至个人能够自动订购产品提供Web服务,它将非常有用。与大部分动态Web应用程序一样,Web服务可以从多层架构的关注点分离中受益。业务逻辑和数据可以由自动客户端和图形用户界面客户端共享,不同点在于客户端的本质和中间的表示层。此外,从数据访问中分离业务逻辑可实现数据库独立性,并为各种类型的数据存储提供插件能力。
图1-8是自动化客户端架构,包括Java和各种语言编写的脚本,这些语言包括Perl、Ruby、PHP、Python或命令行工具(如Curl)。在浏览器中运行且作为RESTful Web服务消费者运行的Ajax、Flash、JavaFX、GWT、博客和WiKi都属于此列,因为它们都代表用户以自动化方式运行。自动化Web服务客户端在Web层向资源请求处理程序发送HTTP响应。客户端的无状态请求在头部包含方法信息,即POST、GET、PUT和DELETE,这又将映射到资源请求处理程序中的相应操作。每个请求都包含所有必需的信息,包括资源请求处理程序用来处理请求的依据。
从Web服务客户端收到请求之后,资源请求处理程序从业务逻辑层请求服务。资源请求处理程序确定所有概念性的实体,系统将这些实体作为资源公开,并为每个资源分配唯一的URI。但是,概念性的实体在该层是不存在的,它们存在于业务逻辑层。可以使用Jersey或其他框架(如Restlet)实现资源请求处理程序,它应该是轻量级的,将大量工作委托给业务逻辑层。
Ajax和RESTful Web服务本质上是互为补充的。它们都可以利用大量Web技术和标准,例如HTML、JavaScript、浏览器对象、XML/JSON和HTTP。当然也不需要购买、安装或配置任何主要组件支持Ajax前端和RESTful Web服务之间的交互。RESTful Web服务为Ajax提供了非常简单的API,以处理服务器端资源之间的交互。
图1-8中的浏览器客户端作为图形用户界面的前端,使用表示层中的浏览器请求处理程序生成HTML提供显示功能。浏览器请求处理程序可以使用模型-视图-控制器模型(Struts、JSF或Spring都是Java的示例)。它从浏览器接收请求,从业务逻辑层请求服务,生成表示并对浏览器做出响应。表示供用户在浏览器中显示使用。表示不仅包含内容,还包含显示的属性,如HTML和CSS(Cascading Style Sheets,串联样式表)。
图1-8 自动化客户端架构
业务规则可以集中到业务逻辑层,该层充当表示层和数据访问层之间的数据交换中间层。数据以域对象或值对象的形式提供给表示层。从业务逻辑层中解耦浏览器请求处理程序和资源请求处理程序有助于促进代码重用,并能实现灵活和可扩展的架构。此外,由于将来可以使用新的REST和模型-视图-控制器框架,因此实现它们会变得更加容易,无须重写业务逻辑层。
数据访问层提供与数据存储层的交互,可以使用DAO设计模式或者对象-关系映射解决方案(如Hibernate、OJB或iBatis/Mybatis)实现。作为替代方案,业务逻辑层和数据访问层中的组件可以实现为EJB组件,并取得EJB容器的支持,该容器可以为组件生命周期提供便利,管理持久性、事务和资源配置。但是,这需要一个遵从Java EE的应用服务器(如JBoss),并且可能无法处理Tomcat。该层的作用在于针对不同的数据存储技术,从业务逻辑层中分离数据访问代码。数据访问层可以作为连接其他系统的集成点,还可以成为其他Web服务的客户端。
数据存储层包括数据库、LDAP服务器、文件系统和遗留系统。使用该架构,可以看到RESTful Web服务的力量,它可以灵活地成为任何企业数据存储的统一API,从而向以用户为中心的Web应用程序公开垂直数据,并自动化批量报告脚本。
REST描述了一个架构样式的互联系统(如Web应用程序)。REST约束条件作为一个整体应用时,将生成一个可扩展、简单、有效、安全和可靠的架构。由于具有简便、轻量级以及通过HTTP直接传输数据的特性,RESTful Web服务成为基于SOAP服务的一个最有前途的替代方案。用于Web服务和动态Web应用程序的多层架构,可以实现重用性、简单性、扩展性和组件响应性的清晰分离。开发人员可以轻松使用Ajax和RESTful Web服务一起创建丰富的界面。
RESTful的关键是定义可表示流程元素/资源的对象。在REST中,每一个对象都是通过URL来表示的,对象用户负责将状态信息打包进每一条消息内,以便对象的处理总是无状态的。RESTful是组合管理及流程绑定,适应企业等级的发现、绑定的灵活性和复杂性。
OCF使用RAML(RESTful API Modeling Language,RESTful API建模语言)描述,RAML是对RESTful API的一种简单和直接的描述。它是一种让人们易于阅读,并且能让机器对特定的文档解析的语言。RAML基于YAML(Yet Another Markup Language,又一种标识语言),能帮助设计RESTful API和鼓励对API的发掘和重用,依靠标准和最佳实践,从而编写更高质量的API。通过RAML定义,机器能够看得懂,所以可以衍生出一些附加的功能服务,例如,解析并自动生成对应的客户端调用代码、服务器端代码结构及API的说明文档。
RAML本质上可以理解为一种文档的书写格式,这种格式是特别针对API的,就像Markdown是针对HTML的一样。并且,RAML也同样具备了像Markdown那样的可读性,即使看RAML源码也能很快明白其意图。另外,基于RAML语言,有不少辅助API开发的工具,如RAML2HTML和API-Console,它们都可以将RAML源文件转换成精美的文档页面,其中,RAML2HTML转换结果是静态的,API-Console则可以产生可直接交互的API文档页面,类似1.6节介绍的Swagger。