JSON

基于 REST 的 Web 服务:基础

字号+ 作者:H5之家 来源:H5之家 2015-10-01 18:03 我要评论( )

代表性状态传输(Representational State Transfer,REST)在 Web 领域已经得到了广泛的接受,是基于 SOAP 和 Web 服务描述语言(Web Services Description Lang

基础

REST 定义了一组体系架构原则,您可以根据这些原则设计以系统资源为中心的 Web 服务,包括使用不同语言编写的客户端如何通过 HTTP 处理和传输资源状态。 如果考虑使用它的 Web 服务的数量,REST 近年来已经成为最主要的 Web 服务设计模型。 事实上,REST 对 Web 的影响非常大,由于其使用相当方便,已经普遍地取代了基于 SOAP 和 WSDL 的接口设计。

REST 这个概念于 2000 年由 Roy Fielding 在就读加州大学欧文分校期间在学术论文“Architectural Styles and the Design of Network-based Software Architectures”(请参见以获取此论文的链接)首次提出,他的论文中对使用 Web 服务作为分布式计算平台的一系列软件体系结构原则进行了分析,而其中提出的 REST 概念并没有获得现在这么多关注。 多年以后的今天,REST 的主要框架已经开始出现,但仍然在开发中,因为它已经被广泛接纳到各个平台中,例如通过 JSR-311 成为了 Java™ 6 不可或缺的部分。

本文认为,对于今天正在吸引如此多注意力的最纯粹形式的 REST Web 服务,其具体实现应该遵循四个基本设计原则:

下面几个部分将详述这四个原则,并提供技术原理解释,说明为什么这些原则对 REST Web 服务设计人员非常重要。

显式地使用 HTTP 方法

基于 REST 的 Web 服务的主要特征之一是以遵循 RFC 2616 定义的协议的方式显式使用 HTTP 方法。例如,HTTP GET 被定义为数据产生方法,旨在由客户端应用程序用于检索资源以从 Web 服务器获取数据,或者执行某个查询并预期 Web 服务器将查找某一组匹配资源然后使用该资源进行响应。

REST 要求开发人员显式地使用 HTTP 方法,并且使用方式与协议定义一致。 这个基本 REST 设计原则建立了创建、读取、更新和删除(create, read, update, and delete,CRUD)操作与 HTTP 方法之间的一对一映射。 根据此映射:

许多 Web API 中所固有的一个令人遗憾的设计缺陷在于将 HTTP 方法用于非预期用途。 例如,HTTP GET 请求中的请求 URI 通常标识一个特定的资源。 或者,请求 URI 中的查询字符串包括一组参数,这些参数定义服务器用于查找一组匹配资源的搜索条件。 至少,HTTP/1.1 RFC 是这样描述 GET 方法的。 但是在许多情况下,不优雅的 Web API 使用 HTTP GET 来触发服务器上的事务性操作——例如,向数据库添加记录。 在这些情况下,GET 请求 URI 属于不正确使用,或者至少不是以基于 REST 的方式使用。 如果 Web API 使用 GET 调用远程过程,则应该类似如下:

GET /adduser?name=Robert HTTP/1.1

这不是非常优雅的设计,因为上面的 Web 方法支持通过 HTTP GET 进行状态更改操作。 换句话说,该 HTTP GET 请求具有副作用。 如果处理成功,则该请求的结果是向基础数据存储区添加一个新用户——在此例中为 Robert。 这里的问题主要在语义上。 Web 服务器旨在通过检索与请求 URI 中的路径(或查询条件)匹配的资源,并在响应中返回这些资源或其表示形式,从而响应 HTTP GET 请求,而不是向数据库添加记录。 从该协议方法的预期用途的角度看,然后再从与 HTTP/1.1 兼容的 Web 服务器的角度看,以这种方式使用 GET 是不一致的。

除了语义之外,GET 的其他问题在于,为了触发数据库中的记录的删除、修改或添加,或者以某种方式更改服务器端状态,它请求 Web 缓存工具(爬网程序)和搜索引擎简单地通过对某个链接进行爬网处理,从而意外地做出服务器端更改。 克服此常见问题的简单方法是将请求 URI 上的参数名称和值转移到 XML 标记中。 这样产生的标记是要创建的实体的 XML 表示形式,可以在 HTTP POST 的正文中进行发送,此 HTTP POST 的请求 URI 是该实体的预期父实体(请参见清单 1 和 2):

清单 1. 之前

GET /adduser?name=Robert HTTP/1.1

清单 2. 之后

POST /users HTTP/1.1 Host: myserver Content-Type: application/xml <?xml version="1.0"?> <user> <name>Robert</name> </user>

上述方法是基于 REST 的请求的范例: 正确使用 HTTP POST 并将有效负载包括在请求的正文中。 在接收端,可以通过将正文中包含的资源添加为请求 URI 中标识的资源的从属资源,从而处理该请求;在此例下,应该将新资源添加为 /users 的子项。 POST 请求中指定的这种新实体与其父实体之间的包含关系类似于某个文件从属于其父目录的方式。 客户端设置实体与其父实体之间的关系,并在 POST 请求中定义新实体的 URI。

然后客户端应用程序可以使用新的 URI 获取资源的表示形式,并至少逻辑地指明该资源位于 /users 之下,如清单 3 所示。

清单 3. HTTP GET 请求

GET /users/Robert HTTP/1.1 Host: myserver Accept: application/xml

以这种方式使用 GET 是显式的,因为 GET 仅用于数据检索。 GET 是应该没有副作用的操作,即所谓的等幂性 属性。

当支持通过 HTTP GET 执行更新操作时,也需要应用类似的 Web 方法重构,如清单 4 所示。

清单 4. 通过 HTTP GET 进行更新

GET /updateuser?name=Robert&newname=Bob HTTP/1.1

这更改了资源的 name 特性(或属性)。 虽然可以将查询字符串用于此类操作,清单 4 就是一个简单的例子,但是在用于较复杂的操作时,这种将查询字符串作为方法签名的模式往往会崩溃。 由于您的目标是显式使用 HTTP 方法,鉴于上述的相同原因(请参见清单 5),更符合 REST 的方法是发送 HTTP PUT 请求以更新资源,而不是发送 HTTP GET。

清单 5. HTTP PUT 请求

PUT /users/Robert HTTP/1.1 Host: myserver Content-Type: application/xml <?xml version="1.0"?> <user> <name>Bob</name> </user>

使用 PUT 取代原始资源可以提供更清洁的接口,这样的接口与 REST 的原则以及与 HTTP 方法的定义一致。 清单 5 中的 PUT 请求是显式的,因为它通过在请求 URI 中标识要更新的资源来指向该资源,并且它在 PUT 请求的正文中将资源的新表示形式从客户端传输到服务器,而不是在请求 URI 上将资源属性作为参数名称和值的松散集合进行传输。 清单 5 还具有将资源从 Robert 重命名为 Bob 的效果,这样做会将其 URI 更改为 /users/Bob。 在 REST Web 服务中,使用旧的 URI 针对该资源的后续请求会产生标准的 404 Not Found 错误。

作为一般设计原则,通过在 URI 中使用名词而不是动词,对于遵循有关显式使用 HTTP 方法的 REST 指导原则是有帮助的。 在基于 REST 的 Web 服务中,协议已经对动词(POST、GET、PUT 和 DELETE)进行了定义。 在理想的情况下,为了保持接口的通用化,并允许客户端明确它们调用的操作,Web 服务不应该定义更多的动词或远程过程,例如 /adduser 或 /updateuser。 这条通用设计原则也适用于 HTTP 请求的正文,后者旨在用于传输资源状态,而不是用于携带要调用的远程方法或远程过程的名称。

无状态

 

1.本站遵循行业规范,任何转载的稿件都会明确标注作者和来源;2.本站的原创文章,请转载时务必注明文章作者和来源,不尊重原创的行为我们将追究责任;3.作者投稿可能会经我们编辑修改或补充。

相关文章
  • 创建 REST API 的最佳入门教程

    创建 REST API 的最佳入门教程

    2015-11-23 17:25

  • spring mvc实现Restful返回json格式数据

    spring mvc实现Restful返回json格式数据

    2015-11-14 14:02

  • nodejs 获取restful api json数据返回到浏览器

    nodejs 获取restful api json数据返回到浏览器

    2015-11-01 08:05

  • 10 个技巧让你的 RESTful Web 服务更加实用

    10 个技巧让你的 RESTful Web 服务更加实用

    2015-10-08 08:14

网友点评
)