您的位置:首页 > 理论基础 > 计算机网络

最佳实践:更好的设计你的 REST API

2015-01-08 16:49 232 查看
最佳实践:更好的设计你的 REST API
由于 REST
可以降低开发的复杂度,提高系统的可伸缩性,增强系统的可扩展性,简化应用系统之间的集成,因而得到了广大开发人员的喜爱,同时得到了业界广泛的支持。比如 IBM,Google
等公司的很多产品都提供了 REST API
给开发人员;与此同时,大量的开源项目和云计算服务都提供了REST API
接口。
而在最近,一些新产品的开发甚至已经几乎完全抛弃了传统的类似 JSP
的技术,转而大量使用 REST
风格的构架设计,即在服务器端所有商业逻辑都以 REST API
的方式暴露给客户端,所有浏览器用户界面使用 widget,Ajax,HTML5
等技术,用 HTTP
的方式与后台直接交互。
那么,在 REST API
爆炸式增长的今天,我们应该如何更好的设计我们的接口,来提高我们的 API
的可用性,易用性,可维护性与可扩展性呢?本文将从以下方面与您探讨REST API
设计方面的最佳实践:
如何规划资源标识结构与 URI
模式
如何根据应用场景提供内容协商
如何正确的使用 HTTP
响应代码
如何处理缓存和并发请求
如何利用数据冗余和链接元素
理解和使用内容协商
我们的开发者在发送一个 REST API
请求的同时,根据应用场景,针对相同的资源,可能会期待不同的返回形式。
比如,我希望根据用户客户端语言,同一个资源的内容可以返回不同的语言。又比如,当我使用 Java
编程的时候,我希望得到 ATOM
格式的返回结果,而当我使用 JavaScript
编程的时候,我希望得到Json
格式的返回结果。
因此,我们在设计 REST API
的时候,应该提供完备的内容协商能力。
使用 URL 参数进行内容协商
最容易想到的自然是通过 URL
参数进行控制,我们经常看到形如 /
航班号 /entry? format=JSON
这样的 URL。这种方式的优势就是简单灵活,你可以通过任何 URL
参数来组合你的输出格式。
下面是一个来自 IBM developerWorks
的API
样例,尝试请求该 API,你可以看到该集合是如何支持不同的输出格式请求的。
清单 3.IBM developerWorks 的文件服务标签云的 API

 REST API 请求,要求返回 XML 格式数据:
 GET  https://www.ibm.com/developerworks/mydeveloperworks  /files/form/anonymous/api/tags/feed?format=xml
 &scope=document&pageSize=30&sK=cloud&sO=dsc
 
 REST API 请求,要求返回 JSON 格式数据:
 GET https://www.ibm.com/developerworks/mydeveloperworks
 /files/form/anonymous/api/tags/feed?format=json
 &scope=document&pageSize=30&sK=cloud&sO=dsc

使用 Accept 头进行内容协商
使用 URL
参数,简单灵活,但是也由此带来了设计上的随意和不标准。并且,过多的参数会导致 URL
的可读性变差,更有甚者,可能会导致URL
过长,超出规范,API
请求无法执行。
更为标准的内容协商方式是使用 HTTP
头。我们通常使用 Accept
来设置我们接受的返回结果的内容格式,用 Accept-Charset
来设置字符集,用Accept-Encoding
来设置数据传输格式,用 Accept-Language
来设置语言。
使用 URI 模式进行内容协商
还有一种模式,就是将协商设置直接作为URI
的一部分,将不同的返回视为不同的资源,比如/
航班号 /json
来返回 JSON 格式的结果,用 /
航班号 /atom
来返回 ATOM 格式的结果。
正确的使用 HTTP 响应代码
作为 API
的设计者,正确的将 API
执行结果和失败原因用清晰简洁的方式传达给客户程序是十分关键的一步。我们确实可以在 HTTP
的相应内容中描述是否成功,如果出错是因为什么,然而,这就意味着用户需要进行内容解析,才知道执行结果和错误原因。因此,HTTP
响应代码可以保证客户端在第一时间用最高效的方式获知API
运行结果,并采取相应动作。下表列出了比较常用的响应代码。
表 1.常用 HTTP 响应代码含义
HTTP 响应代码
代码含义
200
已创建,请求成功且服务器已创建了新的资源。
201
是否只显示处于警告状态的应用实例
301
重定向 , 请求的网页已被永久移动到新位置。服务器返回此响应时,会自动将请求者转到新位置。
302
重定向 , 请求的网页临时移动到新位置,但求者应继续使用原有位置来进行以后的请求。302 会自动将请求者转到不同的临时位置。
304
未修改,自从上次请求后,请求的网页未被修改过。服务器返回此响应时,不会返回网页内容。
400
错误请求 , 服务器不理解请求的语法。
401
未授权 , 请求要求进行身份验证。
403
已禁止 , 服务器拒绝请求。
404
未找到 , 服务器找不到请求的网页。
405
方法禁用 , 禁用请求中所指定的方法。
406
不接受 , 无法使用请求的内容特性来响应请求的网页。
408
请求超时 , 服务器等候请求时超时。
410
已删除 , 如果请求的资源已被永久删除,那么,服务器会返回此响应。
412
未满足前提条件 , 服务器未满足请求者在请求中设置的其中一个前提条件。
415
不支持的媒体类型 , 请求的格式不受请求页面的支持。
500
内部服务器错误。
 
使用 HTTP 头处理缓存和并发
缓存和并发处理,从来是大型软件系统设计中的重要组成部分。
使用 HTTP 头进行缓存处理
在 REST
的构架中,我们除了在与后台的数据交换中,需要有一个良好的缓存机制外,针对 REST API
请求都是在远端用 HTTP
发起这一特点,还需要为网络缓存进行更多考虑。通过减少 HTTP
响应内容,避免不必要的 HTTP
连接等方式,达到提高 REST API
使用效率的目的。
HTTP 头中,有多个字段可以用于缓存处理。比较常用的有缓存控制和条件请求。
缓存控制:
缓存控制通常是需要客户端,缓存服务器 /
代理服务器与业务服务器一起发生作用。
HTTP 头中有“Cache-control”字段来控制如何使用缓存,常见的取值有 private、no-cache、max-age、must-revalidate
等。比如当你给返回的数据内容设置 max-age=600,那么当用户隔了30
秒再次请求的时候,就不会导致重新请求后台数据。
另外,也可以通过“Expires”字段来指定内容过期时间,在此时间前的请求都不会导致后台程序重新请求数据。
下图展示了 max-age
是如何工作的。
图 2.缓存控制工作方式的简单范例





条件请求与电子标签:
很多时候,数据内容可能会几个小时甚至几天都不会发生变动,这个时候根据请求时间间隔来控制缓存,就不能满足系统的需求了。通过支持条件请求与电子标签,可以帮助我们来解决这个问题。
当用户请求数据内容时,系统在返回数据的同时,在 HTTP
头中,将返回根据服务器内容的最后修改时间Last-Modified,或者根据服务器内容生成电子标签 ETag。当用户再次请求数据时,就可以在
HTTP 请求中使用 If-Modified-Since
或者 If-None-Match
头信息,把上次请求得到的时间戳或者电子标签传给服务器。当收到一个有条件请求的 HTTP
头的 REST
请求的时候,我们的程序需要将收到的时间戳或者电子标签与当前内容作比较,就可以很容易的知道用户请求的数据内容在这段时间是否发生过修改,并根据比较结果返回给用户最新内容,或者用 HTTP
响应码 304
告知用户,内容没有变化。
下面是一个来自 IBM developerWorks
的API
样例,尝试请求该 API,你可以看到该 API
会在 HTTP
头中返回电子标签和缓存处理信息。
清单 4.IBM developerWorks 的带有电子标签的文件服务 API

 REST API 请求:
 GET https://www.ibm.com/developerworks/mydeveloperworks
 /form/anonymous/api/communitylibrary
 /7e2e8015-bf72-43b6-bacd-36565b67febc/document
 /ddc0ef4e-224e-449c-bb2c-f919fafb17d2
 /entry?acls=true&includeRecommendation=true
 &includeTags=false&includeLibraryInfo=true&format=xml

使用 HTTP 头进行并发处理
上文我们提到了使用条件请求控制缓存,其实我们还可以使用条件请求进行并发处理。
比如当用户 Alice
和 Bob
通过 REST 获取了一篇文档。Bob
阅读文档之后,通过 PUT
来修改文档;而此前几分钟,Alice
刚刚修改了这篇文档,于是 Bob
就在毫不知情的情况下不慎覆盖了 Alice
的修改。
通过在写操作中支持条件请求,我们可以更好的处理并发修改。用户在发出修改请求的同时,在 HTTP
请求中使用 If-Not-Modified-Since
或者 If-Match
头信息,把获取数据时得到的时间戳或者电子标签传给服务器;我们的程序通过与服务器当前内容的比较,就可以知道,这个修改请求是否是针对当前内容提出的。当服务器发现内容已经被其他用户修改过了,就不会执行修改请求,并返回 HTTP
响应码 412(未满足前提条件)给用户。
下图展示了使用条件请求和电子标签进行并发处理是如何工作的
图 3.支持条件请求时的并发处理简单范例





更好的使用数据冗余和链接元素n
在 ATOM
文档中,我们用各种数据元素来传递信息。其中有一类元素叫做链接,可以用于开发者的进一步访问。通常,我们会提供编辑当前资源的链接,访问当前资源的链接,等等。通过更加灵活的使用这类链接元素,以及提供必要的数据冗余,我们可以大大简化开发者的编程逻辑,提高 REST API
的使用效率
更多的需要注意的细节与技巧
除了以上提到的方面,还有大量的细节与技巧,可以帮助我们更好的设计REST API:
批量更新:
当用户需要更新多个资源的时候,你打算让开发者一次次的发送 HTTP
请求逐个更新吗?你可以考虑在设计 API
的时候允许客户同时创建或者更新多个资源。
REST 安全:
除了使用固有的 HTTP
基本验证,你还可以考虑通过支持表单验证,LTPA验证,Open ID
验证等方式,来满足更多的企业安全要求。
文档服务:
是否由于 API
持续更新,使得客户端连接不同版本服务的时候疲于奔命?尝试着把你的API
定义规范成 XML
文档,这样客户端很容易理解当前服务可以提供哪些功能,以及如何使用这些功能。
你还可以通过阅读其他文档得到更多这方面的指导,本文无法将所有的细节与技巧一一穷尽。
 原文链接:http://www.ibm.com/developerworks/cn/web/1103_chenyan_restapi/
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  RESTful HTTP header