RESTful服务至上实践

过多天没见着楼房了,到木伦终于算是进城了。不止洗上了热水澡,还吃上了麻辣的泡菜汤!——这叫个幸福呵!没能舍得如此的甜美,就毅然决定在这一个没什么景点的市区里就是呆了两天,何人知道接下去是何许的条件在等着自身吧。

正文紧要读者

宗教 1

引言

宗教 2

REST是什么

木伦荒废的广场

  统一接口

喝了两天泡菜汤后踏上了去库苏古尔湖的路,因为是太过名胜的游览景区,也就搭不到哪边便车了。不过话说回来,在蒙古,任何一辆私家车都得以作为出租车来讲价钱,而且并不贵。在多哥洛美搭私家车的价位和公交并不会差太远。八十来英里的路,一人60元人民币便到了这么些来库苏古尔湖亟须停留的小村落——哈特(哈特(Hart))噶勒。

    据悉资源

来蒙古尚无不骑马的道理,但在蒙古逗留的年华并不多了,想骑马看最好的景致需要五六天。自然也就摈弃了,所以第二天便包了辆车,计划沿湖去到一个山脚,然后登顶,把库苏古尔尽收眼底。

    通过特征来操作资源

宗教 3

    自描述的信息

把库苏古尔尽收眼底

    超媒体即采取状态引擎(HATEOAS)

而我平昔以来都是欣赏有水的地方,在洱海边的茂名一呆就是三三个月。吉安也好,明斯克也好,停留可以超越一个月的地点都是有水的。水是可以稀释时间的东西。

  无状态

我们包了一辆小车,还带了两把铁锹,以防进山后车陷进雪地里。买足干粮便扎进车里,又三回开进无从辨识的荒路。联系包车的长兄告诉我们村里住了一对来传教的美利坚联邦合众国小两口,不知怎地,和卡卡从宗教一路聊到了吉普赛人,从吉普赛女小说家巴布莎,聊到了梭罗的《瓦尔登湖》。这多少个全无可比性的人,可以部分共同点,大抵就是“自由”了。我不精通怎么才能形容得了瓦尔登湖给自家的影响,就像心底里的一个梦,一个从未有过有勇气去付诸实践的梦。

  可缓存

宗教 4

  C-S架构

第一眼观察库苏古尔湖

  分层系统

当车翻过最后一个小丘,碧蓝碧蓝的湖从天上掉了下来,没忍住就流了眼泪。什么事物一股脑地从体内冲到眼前,被头上、脸上这层人皮包裹着膨胀起来,哗的刹这就从眼睛里流了出来。

  按需编码(可选)

宗教 5

REST急速指示

宗教 6

  接纳HTTP动词表示一些意义

除去拍摄,我怎么也做不了。一边抹眼泪,一边按着快门。库苏古尔留不下我,却连连地从我体内将眼泪抽了去,融化在他的碧蓝里。一路上就起先沉默着望着窗外的湖水,颠颠簸簸地沿湖岸走了几十公里,直到无路可走。

  客观的资源名

宗教 7

  XML和JSON

宗教 8

  成立适当粒度的资源

上任,背对着湖开头爬山,深一脚浅一脚地走在即将及膝的雪地里,情绪才稍有东山再起。三毛在《万水千山》里,提到过一个非洲的“心湖”,她笃定那是他上辈子生活的出生地。我没可能有这种信任,难过的可能唯有是本身尚未这种信任。既没勇气向梭罗这样在湖边亲手搭起一幢小屋,观看木纹的走向和湖泊结冰的水彩;也没有勇气向三毛这样抛下伙伴和当地人一起种菜放牛。把眼泪还给库苏古尔后,如故要回去自己的准则。按着行程走剩下的路,回到城市,回到生活,回到朝九晚五和这一个快到不可想像的一代。

  设想连通性

宗教 9

定义

爬山

  幂等性

宗教 10

  安全

遇见马

HTTP动词

宗教 11

  GET

宗教 12

  PUT

宗教 13

  POST

快要到达山顶

  PUT和POST的创制比较

从山上下来,只因为刚刚随口一句要尝一尝这湖水,拉我们来的车手便将曾经灌满的水瓶递给了我。回到旅社,天已是黑得透透的了。还有四天蒙古的签证便到期了,为了赶去蒙俄边防,不敢多耽误,第二天早晨就又起身了。

  DELETE

宗教 14

资源命名

宗教 15

  资源URI示例

  资源命名的反例

  复数

归来表征

  资源通过链接的可发现性(HATEOAS续)

    小小的化链接推荐

    链接格式

  卷入响应

  处理跨域问题

    支持CORS

    支持JSONP

询问,过滤和分页

  结果限制

    用范围标记举办界定

    用字符串查询参数进行限定

    基于范围的响应

  分页

  结果的过滤和排序

    过滤

    排序

服务版本管理

  经过情节协商襄助版本管理

  当没有点名版本时,重返什么版本?

  恳请不辅助的本子

  哪些时候理应创制一个新本子?

    破坏性的修改

    非破坏性的改动

  版本控制应在咋样级别出现?

  采取Content-Location来加强响应

  带有Content-Type的链接

  找出扶助的本子

    自我应该而且援助多少个本子?

    弃用

    我哪些告知客户端被弃用的资源?

日期/时间拍卖

  Body内容中的日期/时间连串化

  HTTP
Headers中的日期/时间体系化

护卫服务的本溪

  身份验证

  传输安全

  授权

  应用程序安全

缓存和可伸缩性

  ETag Header

HTTP状态码(前10)

外加资源

  书籍

  网站

 

正文紧要读者

  该最佳实践文档适用于对RESTful
Web服务感兴趣的开发人士,该服务为跨五个服务的机件提供了较高的可靠性和一致性。遵照本文的率领,可迅速、广泛、公开地为内外部客户采取。

  本文中的指点标准一致适用于工程师们,他们期待拔取这个依据最佳实践标准开发的劳务。即便他们进一步尊崇缓存、代理规则、监听及安全等有关地点,可是该文档能作为一份包含所有品类服务的总指南。

  此外,通过从那么些指点原则,管理人士了解到开创公共的、提供高稳定性的劳动所需花费的鼎力,他们也可从中收益。

 

引言

  现今已有雅量关于RESTful
Web服务至上实践的连锁材料(详见本文最终的相关文献部分)。由于撰文的日子不一,许多材料中的内容是争辩的。此外,想要通过翻看文献来询问这种服务的上进是不太可取的。为了领悟RESTful这一定义,至少需要查阅三到五本有关文献,而本文将可以帮你加快这一经过——屏弃多余的议论,最大化地提炼出REST的特等实践和正式。

  与其说REST是一套标准,REST更像是一种规格的会聚。除了六个重大的尺度外就从不任何的标准了。实际上,即便有所谓的“最佳实践”和标准,但这一个事物都和宗教斗争一样,在时时刻刻地衍生和变化。

  本文围绕REST的广阔问题指出了见识和仿食谱式的商讨,并透过介绍部分简短的背景知识对成立真实情状下的预生产环境中相同的REST服务提供文化。本文收集了来自另外渠道的音信,经历过一次次的挫败后不断立异。

  但对此REST格局是否肯定比SOAP好用仍有较大争议(反之亦然),也许在少数情状下仍需要创建SOAP服务。本文在提及SOAP时并未花较大篇幅来商讨它的相对优点。相反由于技术和行业在不断提高,我们将连续坚定不移大家的倘诺–REST是随即计划web服务的特等办法。

  第一有些概述REST的意义、设计准则和它的不同通常之处。第二局部罗列了一部分小贴士来记忆REST的劳务意见。之后的片段则会更透彻地为web服务创设人士提供一些细节的协助和商讨,来兑现一个力所能及公开展示在生养条件中的高质料REST服务。

 

REST是什么?

  REST架构模式讲述了六种设计准则。这么些用于架构的计划性准则,最早是由Roy菲尔德(Field)(Field)ing在她的硕士论文中提议并定义了RESTful风格。(详见http://www.ics.uci.edu/~fielding/pubs/dissertation/rest_arch_style.htm

  六个规划准则分别是:

  • 合并接口
  • 无状态
  • 可缓冲
  • C-S架构
  • 支行系统
  • 按需编码

  以下是那一个规划准则的事无巨细谈论:

合并接口

  统一接口准则定义了客户端和服务端之间的接口,简化和分手了框架结构,这样一来每个部分都可单独衍变。以下是接口统一的六个规格:

  基于资源

  不同资源需要用URI来唯一标识。重回给客户端的表征和资源本身在概念上有所不同,例如服务端不会直接传送一个数据库资源,但是,一些HTML、XML或JSON数据可知呈现部分数据库记录,如用印度语印尼语来表述如故用UTF-8编码则要依照请求和服务器实现的底细来决定。

  通过特征来操作资源

  当客户端收到包含元数据的资源的特点时,在有权力的情状下,客户端已控制的够用的信息,可以对服务端的资源拓展删改。

  自描述的音信

  每条音讯都包含充裕的数量用于确认音信该怎么处理。例如要由网络媒体类型(已知的如MIME类型)来承认需调用哪个解析器。响应同样也标志了它们的缓存能力。

  超媒体即拔取状态引擎(HATEOAS)

  客户端通过body内容、查询串参数、请求头和URI(资源名称)来传送状态。服务端通过body内容,响应码和响应头传送状态给客户端。这项技艺被称呼超媒体(或超文本链接)。

  除了上述内容外,HATEOS也象征,必要的时候链接也可被含有在回到的body(或头部)中,以提供URI来探寻对象自我或涉及对象。下文将对此举行更详细的解说。

  统一接口是各类REST服务计划时的必要准则。

无状态

  正如REST是REpresentational State
Transfer的缩写,无状态很关键。本质上,这标志了拍卖请求所需的情状已经包含在呼吁我里,也有可能是URI的一有些、查询串参数、body或头部。URI可以唯一标识每个资源,body中也富含了资源的转态(或转态变更状况)。之后,服务器将拓展处理,将相关的景观或资源通过头部、状态和响应body传递给客户端。

  从事我们这一行当的绝大多数人都习惯使用容器来编程,容器中有一个“会话”的概念,用于在四个HTTP请求下保持状态。在REST中,虽然要在多个请求下维持用户情形,客户端必须概括客户端的拥有音信来完成请求,必要时再一次发送请求。自从服务端不需要保持、更新或传递会话状态后,无状态性拿到了更大的延展。其它,负载均衡器无需担心和无状态系统里头的对话。

  所以状态和资源间有什么差距?服务器对于状态,或者说是应用状态,所关心的点是在目前对话或请求中要成功请求所需的数码。而资源,或者说是资源气象,则是概念了资源特色的多少,例如存储在数据库中的数据。不问可知,应用状态是是随着客户端和请求的转移而更改的数据。相反,资源气象对于发出请求的客户端的话是不变的。

  在网络采纳的某一一定岗位上布置一个回来按钮,是因为它仰望您能按一定的一一来操作吗?其实是因为它违反了无状态的标准。有好多不听从无状态原则的案例,例如3-Legged
OAuth,API调用速度限制等。但如故要尽可能保证服务器中不需要在三个请求下维持利用状态。

可缓存

  在万维网上,客户端可以缓存页面的响应内容。由此响应都应隐式或显式的定义为可缓存的,若不足缓存则要制止客户端在三番一遍呼吁后用旧数据或脏数据来响应。管理得当的缓存会部分地或完全地除了客户端和服务端之间的相互,进一步改良性能和延展性。

C-S架构

  统一接口使得客户端和服务端互相分开。关注分离意味什么?打个假如,客户端不需要仓储数据,数据都留在服务端内部,那样使得客户端代码的可移植性得到了擢升;而服务端不需要考虑用户接口和用户状况,这样一来服务端将越加简明易拓展。只要接口不转移,服务端和客户端可以独立地拓展研发和替换。

分段系统

  客户端经常不可能阐明自己是直接或者直接与端服务器举办连接。中介服务器可以经过启用负载均衡或提供共享缓存来进步系统的延展性。分层时一致要考虑安全策略。

按需编码(可选)

  服务端通过传输可实施逻辑给客户端,从而为其暂时拓展和定制功效。相关的例子有编译组件Java
applets和客户端脚本JavaScript。

  听从上述条件,与REST架构风格保持一致,能让各个分布式超媒体系统所有梦想的自然属性,比如高性能,延展性,简洁,可变性,可视化,可移植性和可靠性。

  指示:REST架构中的计划性准则中,唯有按需编码为可选项。假诺某个服务违反了其余随意一项准则,严谨意思上不能够称之为RESTful风格。

 

REST快捷指示

  (依据地点提到的五个规格)不管在技术上是不是RESTful的,这里有一对近似REST概念的指出。听从它们,可以实现更好、更有效的服务:

使用HTTP动词表示一些意义

  任何API的使用者可以发送GET、POST、PUT和DELETE请求,它们很大程度明确了所给请求的目标。同时,GET请求不可能改变任何秘密的资源数量。测量和跟踪仍可能发生,但只会更新数据而不会更新由URI标识的资源数量。

成立的资源名

  合理的资源名称或者路径(如/posts/23而不是/api?type=posts&id=23)可以更彰着一个请求的目标。使用URL查询串来过滤数据是很好的点子,但不应有用于固定资源名称。

  适当的资源名称为服务端请求提供上下文,扩张服务端API的可领会性。通过URI名称分层地翻看资源,可以给使用者提供一个和谐的、容易通晓的资源层次,以在她们的应用程序上使用。资源名称应当是名词,防止为动词。使用HTTP方法来指定请求的动作部分,能让工作越来越的不可磨灭。

XML和JSON

  提出默认辅助json,并且,除非花费很惊人,否则就同时襄助json和xml。在地道图景下,让使用者仅通过改变扩充名.xml和.json来切换类型。其余,对于支撑ajax风格的用户界面,一个被卷入的响应是非凡有帮扶的。提供一个被装进的响应,在默认的仍旧有单独扩大名的情景下,例如:.wjson和.wxml,表明客户端请求一个被打包的json或xml响应(请参见下面的包裹响应)。

  “标准”中对json的渴求很少。并且这个要求只是语法性质的,无关内容格式和布局。换句话说,REST服务端调用的json响应是研商的一部分——在专业中尚无相关描述。更多关于json数据格式可以在http://www.json.org/上找到。

  关于REST服务中xml的利用,xml的正式和约定除了行使语法正确的竹签和文本外没有其他的效应。特别地,命名空间不是也不应该是被应用在REST服务端的左右文中。xml的回到更仿佛于json——简单、容易阅读,没有情势和命名空间的底细突显——仅仅是数量和链接。借使它比这更复杂的话,参看本节的第一段——使用xml的财力是惊人的。鉴于大家的经历,很少有人利用xml作为响应。在它被全然淘汰从前,这是终极一个可被肯定的地方。

创办适当粒度的资源

  一起始,系统中效仿底层应用程序域或数据库架构的API更便于被创建。最终,你会希望将这几个劳动都结合到一块儿——利用多项底层资源缩小通信量。在开创独立的资源之后再创立更大粒度的资源,比从更大的合集中成立较大粒度的资源更是容易一些。从局部小的容易定义的资源起初,成立CRUD(增删查改)功效,可以使资源的创设变得更便于。随后,你可以创设这一个依据用例和削减通信量的资源。

设想连通性

  REST的规律之一就是连通性——通过超媒体链接实现。当在响应中回到链接时,api变的更拥有自描述性,而在未曾它们时服务端还是可用。至少,接口本身可以为客户端提供什么寻找数据的参照。其它,在通过POST方法创制资源时,还可以够拔取头地方包含一个链接。对于响应中帮忙分页的集纳,"first"、
"last"、"next"、和"prev"链接至少是这些实用的。

 

定义

幂等性

  不要从字面意思来领悟什么是幂等性,恰恰相反,这与某些职能紊乱的世界无关。上边是缘于维基百科的表达:

在处理器科学中,术语幂等用于更周详地讲述一个操作,四回或频繁实施该操作发生的结果是一致的。依据使用的上下文,这也许有不同的意义。例如,在章程仍然子例程调用装有副功能的情形下,意味着在第一调用之后被修改的情状也保持不变。

  从REST服务端的角度来看,由于操作(或服务端调用)是幂等的,客户端可以用重新的调用而发出同样的结果——在编程语言中操作像是一个"setter"(设置)方法。换句话说,就是运用三个一样的呼吁与运用单个请求效果等同。注意,当幂等操作在服务器上发出同样的结果(副功效),响应本身可能是见仁见智的(例如在多少个请求之间,资源的情状恐怕会转移)。

  PUT和DELETE方法被定义为是幂等的。查看http请求中delete动词的警告信息,可以参考下文的DELETE部分。GET、HEAD、OPTIO和TRACE方法自从被定义为安全的主意后,也被定义为幂等的。参照下面关于安全的段落。

安全

  来自维基百科:

有些办法(例如GET、HEAD、OPTIONS和TRACE)被定义为安全的办法,这代表它们仅被用来音讯搜索,而无法改变服务器的事态。换句话说,它们不会有副作用,除了相对来说无害的震慑如日志、缓存、横幅广告或计数服务等。任意的GET请求,不考虑采取状态的上下文,都被认为是高枕无忧的。

  由此可见,安全意味着调用的法子不会滋生副效用。因而,客户端可以屡屡使用安全的请求而不用担心对服务端发生其余副成效。这表示服务端必须遵循GET、HEAD、OPTIONS和TRACE操作的景德镇概念。否则,除了对消费端爆发模糊外,它还会促成Web缓存,搜索引擎以及任何活动代理的题目——这将在服务器上发出出人意料的结局。

  按照定义,安全操作是幂等的,因为它们在服务器上发生相同的结果。

  安全的点子被实现为只读操作。但是,安全并不意味着服务器必须每一趟都回去相同的响应。

 

HTTP动词

  Http动词重要坚守“统一接口”规则,并提供给我们相应的按照名词的资源的动作。最重大如故最常用的http动词(或者叫做方法,这样称呼可能更恰当些)有POST、GET、PUT和DELETE。这么些分别对应于创制、读取、更新和删除(CRUD)操作。也有很多任何的动词,可是使用频率相比较低。在这一个使用较少的措施中,OPTIONS和HEAD往往利用得更多。

GET

  HTTP的GET方法用于检索(或读取)资源的多寡。在不利的乞请路径下,GET方法会重返一个xml或者json格式的数据,以及一个200的HTTP响应代码(表示正确再次回到结果)。在错误意况下,它一般再次回到404(不设有)或400(错误的哀告)。

  例如:

*  GET http://www.example.com/customers/12345*
  GET http://www.example.com/customers/12345/orders
  GET http://www.example.com/buckets/sample

  遵照HTTP的设计规范,GET(以及附带的HEAD)请求仅用于读取数据而不转移多少。由此,这种应用办法被认为是高枕无忧的。也就是说,它们的调用没有数量修改或污染的风险——调用1次和调用10次仍然尚未被调用的意义一样。此外,GET(以及HEAD)是幂等的,这象征使用五个相同的呼吁与运用单个的呼吁最后都负有相同的结果。

  不要通过GET显露不安全的操作——它应有永远都无法修改服务器上的其它资源。

PUT

  PUT平常被用来改进资源。通过PUT请求一个已知的资源URI时,需要在伏乞的body中带有对原有资源的翻新数据。

  不过,在资源ID是由客服端而非服务端提供的情景下,PUT同样可以被用来创建资源。换句话说,假若PUT请求的URI中包含的资源ID值在服务器上不设有,则用来成立资源。同时请求的body中必须带有要创造的资源的数据。有人觉得这会生出歧义,所以只有真的需要,使用这种情势来创建资源应该被慎用。

  或者大家也得以在body中提供由客户端定义的资源ID然后使用POST来成立新的资源——倘使请求的URI中不含有要开创的资源ID(参见下边POST的局部)。

  例如:

*  PUT http://www.example.com/customers/12345*
  PUT http://www.example.com/customers/12345/orders/98765
  PUT http://www.example.com/buckets/secret\_stuff

  当使用PUT操作更新成功时,会回来200(或者重回204,表示回去的body中不含有其他内容)。如若采取PUT请求创立资源,成功重返的HTTP状态码是201。响应的body是可选的——假诺提供的话将会损耗更多的带宽。在开创资源时从没必要通过头部的岗位重返链接,因为客户端已经设置了资源ID。请参见下面的重返值部分。

  PUT不是一个安全的操作,因为它会修改(或制造)服务器上的气象,但它是幂等的。换句话说,假诺你接纳PUT创制或者更新资源,然后再一次调用,资源依旧存在并且状态不会发生变化。

  例如,假诺在资源增量计数器中调用PUT,那么那多少个调用方法就不再是幂等的。这种场地有时候会发出,且可能可以验证它是非幂等性的。可是,提议维持PUT请求的幂等性。并强烈提议非幂等性的请求使用POST。

POST

  POST请求平日被用于创建新的资源,特别是被用来成立从属资源。从属资源即归属于另外资源(如父资源)的资源。换句话说,当成立一个新资源时,POST请求发送给父资源,服务端负责将新资源与父资源拓展关联,并分配一个ID(新资源的URI),等等。

  例如:

  POST http://www.example.com/customers
  POST http://www.example.com/customers/12345/orders

  当创造成功时,重临HTTP状态码201,并顺便一个地方头新闻,其中蕴涵指向先导创制的资源的链接。

  POST请求既不是高枕无忧的又不是幂等的,由此它被定义为非幂等性资源请求。使用六个一样的POST请求很可能会造成创造四个饱含相同新闻的资源。

PUT和POST的创办相比较

  不言而喻,大家提出选取POST来创立资源。当由客户端来决定新资源具有咋样URI(通过资源名称或ID)时,使用PUT:即假诺客户端知道URI(或资源ID)是何等,则对该URI使用PUT请求。否则,当由服务器或服务端来控制创办的资源的URI时则动用POST请求。换句话说,当客户端在创立此前不精晓(或不能精通)结果的URI时,使用POST请求来创制新的资源。

DELETE

  DELETE很容易了解。它被用来依据URI标识删除资源。

  例如:

  DELETE http://www.example.com/customers/12345
  DELETE http://www.example.com/customers/12345/orders
  DELETE http://www.example.com/buckets/sample

  当删除成功时,再次来到HTTP状态码200(表示正确),同时会有意无意一个响应体body,body中或许含有了删除项的多少(这会占用部分网络带宽),或者封装的响应(参见下面的重回值)。也足以回到HTTP状态码204(表示无内容)表示没有响应体。不言而喻,可以重临状态码204代表不曾响应体,或者重临状态码200还要附带JSON风格的响应体。

  按照HTTP规范,DELETE操作是幂等的。假使你对一个资源拓展DELETE操作,资源就被移除了。在资源上反复调用DELETE最后促成的结果都如出一辙:即资源被移除了。但假设将DELETE的操功效于计数器(资源内部),则DETELE将不再是幂等的。如前方所述,只要数据尚未被更新,总结和测量的用法如故可被认为是幂等的。指出非幂等性的资源请求使用POST操作。

  可是,这里有一个关于DELETE幂等性的警告。在一个资源上第二次调用DELETE往往会回来404(未找到),因为该资源已经被移除了,所以找不到了。这使得DELETE操作不再是幂等的。假诺资源是从数据库中去除而不是被简单地标记为除去,这种情状需要非常让步。

  下表总括出了紧要HTTP的艺术和资源URI,以及引进的再次回到值:

HTTP请求

/customers

/customers/{id}

GET

200(正确),用户列表。使用分页、排序和过滤大导航列表。

200(正确),查找单个用户。假如ID没有找到或ID无效则赶回404(未找到)。

PUT

404(未找到),除非您想在全部集合中立异/替换每个资源。

200(正确)或204(无内容)。尽管没有找到ID或ID无效则赶回404(未找到)。

POST

201(创立),带有链接到/customers/{id}的职务头信息,包含新的ID。

404(未找到)

DELETE

404(未找到),除非你想删除所有集合——平常不被允许。

200(正确)。假如没有找到ID或ID无效则赶回404(未找到)。

 

资源命名

  除了适当地接纳HTTP动词,在开立一个可以精通的、易于使用的Web服务API时,资源命名可以说是最具有争议和最要害的定义。一个好的资源命名,它所对应的API看起来更直观并且易于使用。相反,即便命名糟糕,同样的API会令人倍感很愚蠢并且难以精通和动用。当你需要为你的新API成立资源URL时,这里有局部小技巧值得借鉴。

  从精神上讲,一个RESTFul
API最终都得以被略去地看成是一堆URI的联谊,HTTP调用这些URI以及部分用JSON和(或)XML表示的资源,它们中有好多饱含了互相关系的链接。RESTful的可寻址能力紧要借助URI。每个资源都有温馨的位置或URI——服务器能提供的每一个得力的信息都得以看作资源来公开。统一接口的条件部分地由此URI和HTTP动词的结合来解决,并符合利用规范和预约。

  在支配你系统中要使用的资源时,使用名词来定名这么些资源,而不是用动词或动作来命名。换句话说,一个RESTful
URI应该提到到一个具体的资源,而不是关乎到一个动作。其余,名词还享有部分动词没有的特性,这也是另一个尽人皆知的因素。

  一些资源的例证:

  • 系统的用户
  • 学员登记的课程
  • 一个用户帖子的岁月轴
  • 关爱其他用户的用户
  • 一篇有关骑马的篇章

  服务套件中的每个资源最少有一个URI来标识。如若这些URI能表示一定的含义并且可以尽量描述它所代表的资源,那么它就是一个最好的命名。URI应该具有可预测性和支行结构,这将促进增强它们的可通晓性和可用性的:可预测指的是资源应该和名称保持一致;而分层指的是数额有所关系上的构造。这并非REST规则或标准,可是它加重了对API的概念。

  RESTful
API是提供给消费端的。URI的名目和布局应该将它所表明的含义传达给顾客。平日我们很难明白数码的边际是何许,不过从你的数量上您应有很有可能去尝尝找到要赶回给客户端的数目是如何。API是为客户端而规划的,而不是为您的数码。

  倘若咱们明天要描述一个囊括客户、订单,列表项,产品等效能的订单系统。考虑一下我们该怎么来讲述在这么些服务中所涉及到的资源的URIs:

资源URI示例

  为了在系统中插入(创造)一个新的用户,我们得以拔取:

  POST http://www.example.com/customers

 

  读取编号为33245的用户音讯:

  GET http://www.example.com/customers/33245

  使用PUT和DELETE来请求相同的URI,可以革新和删除数据。

 

  下面是对成品有关的URI的有些提议:

  POST http://www.example.com/products

  用于创建新的制品。

 

  GET|PUT|DELETE http://www.example.com/products/66432

  分别用于读取、更新、删除编号为66432的出品。

 

  那么,怎么样为用户创立一个新的订单呢?

  一种方案是:

  POST http://www.example.com/orders

  这种格局得以用来成立订单,但贫乏相应的用户数量。

  

  因为我们想为用户创立一个订单(注意之间的涉嫌),这些URI可能不够直观,上边那些URI则更显明一些:

  POST http://www.example.com/customers/33245/orders

  现在大家了解它是为编号33245的用户创立一个订单。

 

  这下边这些请求再次回到的是哪些呢?

  GET http://www.example.com/customers/33245/orders

  可能是一个数码为33245的用户所创设或有所的订单列表。注意:我们可以遮挡对该URI举行DELETE或PUT请求,因为它的操作对象是一个凑合。

 

  继续深远,这下边那么些URI的伸手又代表如何吧?

  POST http://www.example.com/customers/33245/orders/8769/lineitems

  可能是(为编号33245的用户)增添一个编号为8769的订单条目。没错!假如选用GET模式呼吁那些URI,则会再次回到这多少个订单的享有条条框框。不过,假如那几个条款与用户音信无关,我们将会提供POST
www.example.com/orders/8769/lineitems
这个URI。

  从再次回到的这些条款来看,指定的资源可能会有三个URIs,所以我们或许也亟需要提供这么一个URI
GET
http://www.example.com/orders/8769
,用来在不了然用户ID的图景下基于订单ID来查询订单。

 

  更进一步:

  GET http://www.example.com/customers/33245/orders/8769/lineitems/1

  可能只回去同个订单中的第一个条文。

  现在你应有清楚什么是分层结构了。它们并不是严俊的平整,只是为着保证在你的劳务中那么些强制的布局能够更易于被用户所领悟。与拥有软件开发中的技能一样,命名是打响的要紧。

  

  多看有的API的示范并学会控制这些技巧,和您的队友一起来宏观你API资源的URIs。这里有局部APIs的事例:

资源命名的反例

  前边我们早就研商过一些适度的资源命名的事例,然则有时一些反面的事例也很有教育意义。下面是有些不太具有RESTful风格的资源URIs,看起来比较散乱。那多少个都是荒谬的事例! 

  首先,一些serivices往往采纳单一的URI来指定服务接口,然后经过查询参数来指定HTTP请求的动作。例如,要更新编号12345的用户音讯,带有JSON
body的哀告可能是如此:

  GET
http://api.example.com/services?op=update\_customer&id=12345&format=json

  即便地点URL中的"services"的那一个节点是一个名词,但以此URL不是自解释的,因为对于有所的呼吁而言,该URI的层级结构都是一致的。其它,它使用GET作为HTTP动词来举办一个更新操作,这简直就是反人类(甚至是危急的)。

  下边是此外一个翻新用户的操作的例子:

  GET http://api.example.com/update\_customer/12345

  以及它的一个变种:

  GET http://api.example.com/customers/12345/update

  你会不时见到在其他开发者的劳务套件中有这多少个如此的用法。可以看到,那多少个开发者试图去成立RESTful的资源名称,而且早已有了一部分腾飞。但是你照样可以分辨出URL中的动词短语。注意,在这几个URL中大家不需要"update"那几个词,因为大家可以借助HTTP动词来形成操作。下边这个URL正好表达了这点:

  PUT http://api.example.com/customers/12345/update

  那些请求同时存在PUT和"update",这会对顾客发生迷惑!这里的"update"指的是一个资源吗?因而,这里我们费些口舌也是目的在于您可知精通……

复数

  让我们来探讨一下复数和“单数”的争论…还没听说过?但这种争议确实存在,事实上它可以归纳为这一个题材……

  在你的层级结构中URI节点是否需要被取名为单数或复数形式吗?举个例子,你用来寻找用户资源的URI的命名是否需要像上面这样:

  GET http://www.example.com/customer/33245

  或者:

  GET http://www.example.com/customers/33245

  二种办法都没问题,但通常我们都会选取使用复数命名,以使得你的API
URI在具备的HTTP方法中保持一致。原因是依照那样一种考虑:customers是服务套件中的一个相会,而ID33245的那一个用户则是以此集合中的其中一个。

  依据这几个规则,一个利用复数形式的多节点的URI会是如此(注意粗体部分):

  GET
http://www.example.com/**customers**/33245/**orders**/8769/**lineitems**/1

  “customers”、“orders”以及“lineitems”这一个URI节点都接纳的是复数格局。

  这意味你的每个根资源只需要多个要旨的URL就可以了,一个用于创制集合内的资源,另一个用来依据标识符获取、更新和删除资源。例如,以customers为例,创制资源得以应用下边的URL举行操作:

  POST http://www.example.com/customers

  而读取、更新和删除资源,使用上边的URL操作:

  GET|PUT|DELETE http://www.example.com/customers/{id}

  正如前方提到的,给定的资源可能有两个URI,但作为一个纤维的完好的增删改查效率,利用六个大概的URI来拍卖就够了。

  或许你会问:是否在稍微处境下复数没有意义?嗯,事实上是这么的。当没有集合概念的时候(此时复数没有意义)。换句话说,当资源只有一个的情况下,使用单数资源名称也是可以的——即一个纯净的资源。例如,假若有一个十足的完整布局资源,你可以动用一个单数名称来表示:

  GET|PUT|DELETE http://www.example.com/configuration

  注意这里缺乏configuration的ID以及HTTP动词POST的用法。假若每个用户有一个部署来说,那么这么些URL会是这般:

  GET|PUT|DELETE
http://www.example.com/customers/12345/configuration

  同样令人瞩目那里没有点名configuration的ID,以及从未给定POST动词的用法。在这六个例子中,可能也会有人以为采取POST是有效的。好吧...

 

重临表征

  正如前方提到的,RESTful接口援助多种资源特色,包括JSON和XML,以及被包裹的JSON和XML。提出JSON作为默认表征,但是服务端应该允许客户端指定其他表征。

  对于客户端请求的特征格式,我们得以在Accept头通过文件扩展名来进展点名,也能够由此query-string等此外措施来指定。理想图景下,服务端可以支撑所有这一个格局。不过,现在正式更赞成于通过类似于文件增添名的章程来展开点名。由此,提议服务端至少需要扶助拔取文件增加名的不二法门,例如“.json”,“.xml”以及它们的包装版本“.wjon”,“.wxml”。

  通过这种艺术,在URI中指定重返表征的格式,可以增强URL的可见性。例如,GET
http://www.example.com/customers.xml
将重临customer列表的XML格式的风味。同样,GET
http://www.example.com/customers.json
将回来一个JSON格式的特性。这样,尽管是在最基础的客户端(例如“curl”),服务应用起来也会越来越便民。推荐使用这种形式。

  另外,当url中尚无包含格式表明时,服务端应该回到默认格式的特征(倘诺为JSON)。例如:

  GET http://www.example.com/customers/12345

  GET http://www.example.com/customers/12345.json

  以上两者重返的ID为12345的customer数据均为JSON格式,这是服务端的默认格式。

  GET http://www.example.com/customers/12345.xml

  假诺服务端帮助的话,以上请求重回的ID为12345的customer数据为XML格式。假若该服务器不帮助XML格式的资源,将回来一个HTTP
404的不当。

  使用HTTP
Accept头被广大认为是一种更优雅的方法,并且符合HTTP的正式和意义,客户端可以由此这种方法来报告HTTP服务端它们可协助的数据类型有什么。不过,为了接纳Accept头,服务端要同时帮忙封装和未封装的响应,你不可以不实现自定义的体系——因为这一个格式不是正式的体系。这大大扩充了客户端和服务端的复杂性。请参见RFC
2616的14.1节关于Accept头的详细消息(http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.1)。使用文件扩张名来指定数量格式是最简便易行直接的点子,用最少的字符就足以做到,并且辅助脚本操作——无需使用HTTP头。

  常常当我们关系REST服务,跟XML是毫不相关的。虽然服务端辅助XML,也几乎一贯不人提出在REST中运用XML。XML的正式和公约在REST中不太适用。特别是它连命名空间都尚未,就更不该在RESTful服务系列中动用了。这只会使业务变得更扑朔迷离。所以回来的XML看起来更像JSON,它概括易读,没有格局和命名空间的限量,换句话来说是无标准的,易于解析。

资源通过链接的可发现性(HATEOAS续)

  REST带领原则之一(依据统一接口规范)是application的状况通过hypertext(超文本)来传输。这就是我们一般所说的Hypertext
As The Engine of Application State
(即HATEOAS,用超文本来作为应用程序状态机),大家在“REST是什么”一节中也提到过。

  依据RoyFielding在他的博客中的描述(http://roy.gbiv.com/untangled/2008/rest-apis-must-be-hypertextdriven),REST接口中最重大的局部是超文本的接纳。此外,他还指出,在提交任何相关的音信以前,一个API应该是可用和可分晓的。也就是说,一个API应当可以透过其链接导航到多少的逐条部分。不提出只回去纯数据。

  但是当下的业界先驱们并没有日常利用这种做法,这反映了HATEOAS仅仅在成熟度模型中的使用率更高。纵观众多的服务连串,它们大多再次回到更多的数额,而回到的链接却很少(或者没有)。那是违反菲尔德(Field)ing的REST约定的。菲尔德(Field)ing说:“音讯的每一个可寻址单元都辅导一个地方……查询结果应该突显为一个饱含摘要消息的链接清单,而不是目标数组。”

  另一方面,简单粗暴地将总体链接集合重返会大大影响网络带宽。在实际情况中,依据所需的基准或利用状态,API接口的通信量要依据服务器响应中超文本链接所蕴涵的“摘要”数量来抵消。

  同时,丰裕利用HATEOAS可能会追加实现的错综复杂,并对劳动客户端发生彰着的负责,这一定于降低了客户端和劳务器端开发人士的生产力。因而,当务之急是要平衡超链接服务推行和水土保持可用资源之间的题材。

  超链接最小化的做法是在最大限度地减小客户端和服务器之间的耦合的还要,提高服务端的可用性、可操纵性和可明白性。这多少个最小化提出是:通过POST创设资源并从GET请求重临集合,对于有分页的事态后边大家会涉嫌。

微小化链接推荐

  在create的用例中,新建资源的URI(链接)应该在Location响应头中回到,且响应中央是空的——或者只包含新建资源的ID。

  对于从服务端重临的特点集合,每个表征应该在它的链接集合中指点一个不大的“自身”链接属性。为了有利于分页操作,其余的链接可以置身一个单独的链接集合中回到,必要时方可涵盖“第一页”、“上一页”、“下一页”、“最后一页”等信息。

  参照下文链接格式局部的例子获取更多音信。

链接格式

  参照整个链接格式的专业,指出服从一些好像Atom、AtomPub或Xlink的作风。JSON-LD也不利,但并不曾被广大利用(假若已经被用过)。如今标准最广大的模式是使用含有"rel"元素和含有资源全部URI的"href"元素的Atom链接格式,不分包其他身份验证或询问字符串参数。"rel"元素得以蕴涵标准值"alternate"、"related"、"self"、"enclosure"和"via",还有分页链接的“第一页”、“上一页”、“下一页”,“最后一页”。在急需时可以自定义并加上应用它们。

  一些XML
Atom格式的概念对于用JSON格式表示的链接来说是不行的。例如,METHOD属性对于一个RESTful资源来说是不需要的,因为对此一个加以的资源,在享有协助的HTTP方法(CRUD行为)中,资源的URI都是同样的——所以单独列出这么些是平昔不必要的。

  让我们举一些切实可行的例证来更是求证这点。上边是调用创立新资源的伸手后的响应:

  POST http://api.example.com/users

  上边是响应头集合中隐含创立新资源的URI的Location部分:

HTTP/1.1 201 CREATED Status: 201 Connection: close Content-Type: application/json; charset=utf-8 Location: http://api.example.com/users/12346

  重临的body可以为空,或者隐含一个被包裹的响应(见下文封装响应)。

  上面的例证通过GET请求获取一个不分包分页的特性集合的JSON响应:

{ "data": [ { "user_id": "42", "name": "Bob", "links": [ { "rel": "self", "href": "http://api.example.com/users/42" } ] }, { "user_id": "22", "name": "Frank", "links": [ { "rel": "self", "href": "http://api.example.com/users/22" } ] }, { "user_id": "125", "name": "Sally", "links": [ { "rel": "self", "href": "http://api.example.com/users/125" } ] } ]}

  注意,links数组中的每一项都饱含一个针对“自身(self)”的链接。该数组还可能还富含其他关系,如children、parent等。

  最终一个例子是因而GET请求获取一个涵盖分页的特色集合的JSON响应(每页展现3项),大家提交第三页的多寡:

{ "data": [ { "user_id": "42", "name": "Bob", "links": [ { "rel": "self", "href": "http://api.example.com/users/42" } ] }, { "user_id": "22", "name": "Frank", "links": [ { "rel": "self", "href": "http://api.example.com/users/22" } ] }, { "user_id": "125", "name": "Sally", "links": [ { "rel": "self", "href": "http://api.example.com/users/125" } ] } ], "links": [ { "rel": "first", "href": "http://api.example.com/users?offset=0&limit=3" }, { "rel": "last", "href": "http://api.example.com/users?offset=55&limit=3" }, { "rel": "previous", "href": "http://api.example.com/users?offset=3&limit=3" }, { "rel": "next", "href": "http://api.example.com/users?offset=9&limit=3" } ]}

  在这些例子中,响应中用来分页的links集合中的每一项都饱含一个针对性“自身(self)”的链接。这里或许还会有局部涉及到聚集的此外链接,但都与分页本身无关。简单来说,那里有三个地方含有links。一个就是data对象中所包含的集结(这么些也是接口要重回给客户端的数额表征集合),其中的每一项至少要包括一个针对性“自身(self)”的links集合;另一个则是一个独立的目标links,其中包括和分页相关的链接,该片段的始末适用于全部集合。

  对于由此POST请求创立资源的气象,需要在响应头中包含一个提到新建对象链接的Location

包裹响应

   服务器可以在响应中并且再次回到HTTP状态码和body。有好多JavaScript框架没有把HTTP状态响应码再次回到给最终的开发者,这频繁会促成客户端不能遵照事态码来确定具体的行事。其它,尽管HTTP规范中有很多种响应码,不过频繁只有个别客户端会关心这个——经常我们只在乎"success"、"error"或"failture"。因此,将响应内容和响应状态码封装在蕴藏响应音信的表征中,是有必不可少的。

  OmniTI
实验室有如此一个提议,它被号称JSEND响应。更多信息请参考http://labs.omniti.com/labs/jsend。此外一个提案是由DouglasCrockford指出的,可以查看这里http://www.json.org/JSONRequest.html

  那一个提案在实践中并不曾完全涵盖所有的情景。基本上,现在最好的做法是按部就班以下属性封装常规(非JSONP)响应:

  • code——包含一个整数品种的HTTP响应状态码。
  • status——包含文本:"success","fail"或"error"。HTTP状态响应码在500-599里边为"fail",在400-499里边为"error",其余均为"success"(例如:响应状态码为1XX、2XX和3XX)。
  • message——当状态值为"fail"和"error"时有效,用于展示错误音讯。参照国际化(il8n)标准,它可以涵盖音信号或者编码,能够只包含其中一个,或者同时含有并用分隔符隔开。
  • data——包含响应的body。当状态值为"fail"或"error"时,data仅包含错误原因或特别名称。

  下边是一个回来success的包裹响应:

{ "code": 200, "status": "success", "data": { "lacksTOS": false, "invalidCredentials": false, "authToken": "4ee683baa2a3332c3c86026d" }}

  重返error的卷入响应:

{ "code": 401, "status": "error", "message": "token is invalid", "data": "UnauthorizedException"}

  这六个包裹响应对应的XML如下:

<response> <code>200</code> <status>success</status> <data class="AuthenticationResult"> <lacksTOS>false</lacksTOS> <invalidCredentials>false</invalidCredentials> <authToken>1.0|idm|idm|4ee683baa2a3332c3c86026d</authToken> </data></response>

  和:

<response> <code>401</code> <status>error</status> <message>token is invalid</message> <data class="string">UnauthorizedException</data></response>

拍卖跨域问题

   我们都听说过有关浏览器的同源策略或同源性需求。它指的是浏览器只好请求当前正在突显的站点的资源。例如,如若当前正值显示的站点是www.Example1.com,则该站点无法对www.Example.com倡导呼吁。显明这会潜移默化站点访问服务器的方法。

  近日有三个被广泛接受的支撑跨域请求的艺术:JSONP和跨域资源共享(CORS)。JSONP或“填充的JSON”是一种采纳模式,它提供了一个措施请求来自不同域中的服务器的数量。其工作办法是从服务器重回任意的JavaScript代码,而不是JSON。客户端的响应由JavaScript解析器举办分析,而不是直接解析JSON数据。其它,CORS是一种web浏览器的技能专业,它为web服务器定义了一种艺术,从而允许服务器的资源得以被不同域的网页访问。CORS被视作是JSONP的新型替代品,并且可以被有着现代浏览器辅助。因而,不指出利用JSONP。任何情形下,推荐选取CORS。

支持CORS

  在服务端实现CORS很简单,只需要在殡葬响应时顺便HTTP头,例如: 

Access-Control-Allow-Origin: *

  惟有在数量是集体使用的境况下才会将做客来源设置为"*"。大多数情景下,Access-Control-Allow-Origin头应该指定哪些域可以倡导一个CORS请求。只有需要跨域访问的URL才设置CORS头。

Access-Control-Allow-Origin: http://example.com:8080
http://foo.example.com

  以上Access-Control-Allow-Origin头中,被安装为只允许受依赖的域可以访问。

Access-Control-Allow-Credentials: true

  只在需要时才使用方面这多少个header,因为假如用户已经报到的话,它会同时发送cookies/sessions。

  这几个headers可以透过web服务器、代理来拓展布局,或者从服务器本身发送。不推荐在服务端实现,因为很不灵便。或者,可以行使方面的第二种艺术,在web服务器上配置一个用空格分隔的域的列表。更多关于CORS的始末可以参见这里:http://enable-cors.org/

支持JSONP

  JSONP通过采纳GET请求避开浏览器的限定,从而实现对拥有服务的调用。其行事原理是请求方在伸手的URL上添加一个字符串查询参数(例如:jsonp=”jsonp_callback”),其中“jsonp”参数的值是JavaScript函数名,该函数在有响应重临时将会被调用。

  由于GET请求中并未包含请求体,JSONP在动用时有着严重的局限性,因而数据必须通过字符串查询参数来传递。同样的,为了辅助PUT,POST和DELETE方法,HTTP方法必须也经过字符串查询参数来传递,类似_method=POST这种格局。像这么的HTTP方法传送模式是不推荐使用的,这会让服务处于安全风险之中。

  JSONP日常在有的不帮助CORS的老旧浏览器中接纳,假诺要改成援助CORS的,会影响整个服务器的架构。或者我们也足以经过代理来促成JSONP。显而易见,JSONP正在被CORS所替代,我们应该尽可能地采纳CORS。

  为了在服务端匡助JSONP,在JSONP字符串查询参数传递时,响应必须要实践以下这多少个操作:

  1. 响应体必须封装成一个参数传递给jsonp中指定的JavaScript函数(例如:jsonp_callback("<JSON
    response body>"))。
  2. 平昔重临HTTP状态码200(OK),并且将忠实的场所作为JSON响应中的一部分重回。

  此外,响应体中时时必须含有响应头。这使得JSONP回调方法需要依照响应体来规定响应处理情势,因为它自身不能获知真实的响应头和景色值。

  下边的例子是遵照上述措施封装的一个回到error状态的jsonp(注意:HTTP的响应状态是200):

jsonp_callback("{'code':'404', 'status':'error','headers':[],'message':'resource XYZ notfound','data':'NotFoundException'}")

  成功成立后的响应类似于这样(HTTP的响应状态仍是200):

jsonp_callback("{'code':'201', 'status':'error','headers':[{'Location':'http://www.example.com/customers/12345'}],'data':'12345'}")

 

查询,过滤和分页

  对于大数据集,从带宽的角度来看,限制重回的数据量是老大重大的。而从UI处理的角度来看,限制数据量也同等举足轻重,因为UI平日只可以展现大数目汇总的一小部分数据。在数据集的增长速度不确定的状态下,限制默认再次来到的数据量是很有必不可少的。以Twitter为例,要得到某个用户的推文(通过个人主页的大运轴),假诺没有特意指定,请求默认只会回来20条记下,即使系统最多可以回去200条记下。

  除了限制重返的数据量,我们还亟需考虑怎么对天意据集举办“分页”或下拉滚动操作。创设数量的“页码”,重返大数据列表的已知片段,然后标出数据的“前一页”和“后一页”——这一作为被称之为分页。其余,大家或许也亟需指定响应上校包含哪些字段或性能,从而限制再次回到值的数码,并且大家希望最后可以通过一定值来拓展询问操作,并对重返值举办排序。

  有二种紧要的不二法门来还要限制查询结果和实施分页操作。首先,大家得以建立一个目录方案,它可以以页码为导向(请求中要付出每一页的记录数及页码),或者以记录为导向(请求中直接交给第一条记下和尾声一条记下)来规定再次来到值的开端地点。举个例子,这二种形式分别代表:“给出第五页(假诺每页有20条记下)的记录”,或“给出第100到第120条的笔录”。

  服务端将遵照运作机制来拓展切分。有些UI工具,比如Dojo
JSON会采取模仿HTTP规范行使字节范围。假诺服务端匡助out of
box(即开箱即用效能),则前端UI工具和后端服务期间无需任何转换,这样使用起来会很便利。

  下文将介绍一种格局,既可以匡助Dojo这样的分页情势(在请求头中提交记录的限量),也能支撑采用字符串查询参数。这样一来服务端将变得更为灵活,既可以采纳类似Dojo一样先进的UI工具集,也足以使用简单直接的链接和标签,而无需再为此增添复杂的支出工作。但假如服务不直接援助UI效率,可以考虑不要在请求头中付出记录范围。

  要专门提出的是,大家并不推荐在颇具服务中应用查询、过滤和分页操作。并不是具有资源都默认补助那多少个操作,只有少数特定的资源才支撑。服务和资源的文档应当表明什么接口帮助这么些复杂的功效。

结果限制

  “给出第3到第55条的笔录”,这种请求数据的情势和HTTP的字节范围规范更平等,由此我们可以用它来标识Range
header。而“从第2条记下先河,给出最多20条记下”这种办法更便于阅读和清楚,因而大家常见会用字符串查询参数的章程来表示。

  综上所述,推荐既辅助使用HTTP Range
header,也支撑使用字符串查询参数——offset(偏移量)和limit(限制),然后在服务端对响应结果开展限定。注意,假若还要协助这二种方法,那么字符串查询参数的先行级要压倒Range
header。

  这里你可能会有个问题:“那三种情势效果相似,可是回到的数目不完全一致。这会不会令人歪曲呢?”恩…这是多少个问题。首先要回应的是,这真的会令人歪曲。关键是,字符串查询参数看起来更为清晰易懂,在构建和剖析时更是便于。而Range
header则更多是由机器来使用(偏向于底层),它进一步契合HTTP使用正规。

  总而言之,解析Range
header的工作会扩大复杂度,相应的客户端在构建请求时也急需展开部分拍卖。而采纳单独的limit和offset参数会更为容易精通和构建,并且不需要对开发人士有更多的渴求。

用范围标记举行限定

  当用HTTP header而不是字符串查询参数来博取记录的限量时,Ranger
header应该经过以下内容来指定范围: 

  Range: items=0-24

  注意记录是从0最先的连续字段,HTTP规范中验证了什么利用Range
header来请求字节。也就是说,要是要呼吁数据汇总的首先条记下,范围应该从0先导算起。上述的哀告将会回到前25个记录,假如数据集中至少有25条记下。

  而在服务端,通过检查请求的Range
header来确定该再次回到哪些记录。只要Range
header存在,就会有一个大概的正则表明式(如"items=(\d+)-(\d+)")对其进行分析,来赢得要摸索的范围值。

用字符串查询参数举办限制

  字符串查询参数被作为Range
header的替代选拔,它应用offset和limit作为参数名,其中offset代表要询问的第一条记下编号(与上述的用于范围标记的items第一个数字同样),limit代表记录的最大条数。下面的例证重返的结果与上述用范围标记的事例一样:

  GET http://api.example.com/resources?offset=0&limit=25

  Offset参数的值与Range
header中的类似,也是从0初始估量。Limit参数的值是回来记录的最大数目。当字符串查询参数中未指定limit时,服务端应当提交一个缺省的最大limit值,可是这一个参数的选用都亟待在文档中举行验证。

依据范围的响应

  对一个基于范围的呼吁来说,无论是通过HTTP的Range
header仍然经过字符串查询参数,服务端都应该有一个Content-Range
header来响应,以标明重回记录的条数和总记录数:

  Content-Range: items 0-24/66

  注意这里的总记录数(如本例中的66)不是从0起先揣测的。假诺要请求数据集中的最终几条记下,Content-Range
header的始末应该是如此:

  Content-Range: items 40-65/66

  依据HTTP的专业,假设响应时总记录数未知或难以总计,也可以用星号("*")来代替(如本例中的66)。本例中响应头也可这样写:

  *Content-Range: items 40-65/**

  然而要留心,Dojo或一些任何的UI工具可能不帮助该符号。

分页

  上述形式经过请求方指定数据集的限定来界定再次来到结果,从而实现分页效用。下边的例证中累计有66条记下,假诺每页25条记下,要彰显第二页数据,Range
header的情节如下:

  Range: items=25-49

  同样,用字符串查询参数表示如下:

  GET …?offset=25&limit=25

  服务端会相应地重回一组数据,附带的Content-Range header内容如下:

  Content-Range: 25-49/66

  在大部分处境下,这种分页格局都未曾问题。但奇迹会有这种意况,就是要赶回的笔录数据不可能直接代表成多少集中的行号。还有就是有些数据集的转变很快,不断会有新的多寡插入到数码集中,这样必然会促成分页出现问题,一些重新的数量可能会现出在不同的页中。

  按日期排列的数据集(例如Twitter
feed)就是一种普遍的景观。即使您要么得以对数据开展分页,但奇迹用"after"或"before"这样的重点字并与Range
header(或者与字符串查询参数offset和limit)配合来贯彻分页,看起来会越加简明易懂。

  例如,要博得给定时间戳的前20条评论:

  GET
http://www.example.com/remarks/home\_timeline?after=&lt;timestamp&gt

  Range: items=0-19

  GET
http://www.example.com/remarks/home\_timeline?before=&lt;timestamp&gt

*  Range: items=0-19*

  用字符串查询参数表示为:

  GET
http://www.example.com/remarks/home\_timeline?after=&lt;timestamp&gt;&offset=0&limit=20 

*  GET
http://www.example.com/remarks/home\_timeline?before=&lt;timestamp&gt;&offset=0&limit=20*

  有关在不同情状对时间戳的格式化处理,请参见下文的“日期/时间拍卖”。

  如果请求时髦未点名要回到的数目范围,服务端重返了一组默认数据或限制的最大数据集,那么服务端同时也应当在回到结果中涵盖Content-Range
header来和客户端举行确认。以地方个人主页的刻钟轴为例,无论客户端是不是指定了Range
header,服务端每一趟都只回去20条记下。此时,服务端响应的Content-Range
header应该包含如下内容:

  Content-Range: 0-19/4125

  或 *Content-Range: 0-19/**

结果的过滤和排序

  针对再次来到结果,还索要考虑什么在服务端对数码举办过滤和排列,以及怎么样按指定的逐条对子数据开展搜索。这个操作可以与分页、结果限制,以及字符串查询参数filter和sort等相结合,可以兑现强大的数据检索功用。

  再强调三遍,过滤和排序都是纵横交错的操作,不需要默认提供给所有的资源。下文将介绍怎么着资源需要提供过滤和排序。

过滤

  在本文中,过滤被定义为“通过一定的条件来确定必须要回去的数据,从而缩短再次来到的数据”。假设服务端支持一套完整的可比运算符和复杂性的尺码配合,过滤操作将变得一定复杂。不过我们通常会使用部分概括的表明式,如starts-with(以...起先)或contains(包含)来开展匹配,以保证重回数据的完整性。

  在大家开始谈论过滤的字符串查询参数从前,必须先了然怎么要采用单个参数而不是六个字符串查询参数。从根本上来说是为着缩小参数名称的争辩。我们早就有offsetlimitsort(见下文)参数了。假设可能的话还会有jsonpformat标识符,或许还会有afterbefore参数,这个都是在本文中涉嫌过的字符串查询参数。字符串查询中接纳的参数越多,就越可能引致参数名称的争辨,而利用单个过滤参数则会将争辩的可能降到最低。

  其它,从服务端也很容易仅透过单个的filter参数来判断请求方是否需要多少过滤效果。假设查询需要的复杂度增添,单个参数将更具有灵活性——可以友善树立一套功用一体化的询问语法(详见下文OData注释或访问http://www.odata.org)。

  通过引入一组广泛的、公认的分隔符,用于过滤的表明式可以以这些直观的款式被使用。用这多少个分隔符来设置过滤查询参数的值,这个分隔符所成立的参数名/值对可以越来越容易地被服务端解析并提升多少查询的特性。近期已部分分隔符包括用来分隔每个过滤短语的竖线("|")和用来分隔参数名和值的双冒号("::")。这套分隔符丰盛唯一,并符合大多数状态,同时用它来构建的字符串查询参数也尤为便于精通。上边将用一个简短的例证来介绍它的用法。假若我们想要给名为“托德(Todd)”的用户们发送请求,他们住在天津,有着“Grand
Poobah”之称。用字符串查询参数实现的请求URI如下:

  GET
http://www.example.com/users?filter="name::todd|city::denver|title::grand
poobah"

  双冒号("::")分隔符将属性名和值分开,这样属性值就可知包含空格——服务端能更便于地从属性值中分析出分隔符。

  注意查询参数名/值对中的属性名要和服务端再次回到的性能名相匹配。

  简单而使得。有关大小写敏感的题目,要按照具体情况来看,但总的看,在毫无关心大小写的事态下,过滤效果可以很好地运转。若查询参数名/值对中的属性值未知,你也得以用星号("*")来代替。

  除了简单的表明式和通配符之外,若要举行更复杂的查询,你必须要引入运算符。在这种状态下,运算符本身也是属性值的一部分,能够被服务端解析,而不是变成属性名的一有些。当需要复杂的query-language-style(查询语言风格)效用时,可参看Open
Data Protocol (OData) Filter System Query
Option表达中的查询概念(详见http://www.odata.org/documentation/uriconventions#FilterSystemQueryOption)。

排序

  排序决定了从服务端再次回到的笔录的相继。也就是对响应中的多条记下进行排序。

  同样,大家这里只考虑部分相比较简单的图景。推荐应用排序字符串查询参数,它涵盖了一组用分隔符分隔的属性名。具体做法是,默认对每个属性名按升序排列,要是属性名有前缀"-",则按降序排列。用竖线("|")分隔每个属性名,这和前边过滤效果中的参数名/值对的做法一样。

  举个例证,假使大家想按用户的姓和名进行升序排序,而对雇佣时间展开降序排序,请求将是这样的:

  GET
http://www.example.com/users?sort=last\_name|first\_name|-hire\_date

  再度强调一下,查询参数名/值对中的属性名要和服务端重回的属性名相匹配。此外,由于排序操作比较复杂,我们只对亟待的资源提供排序效能。假诺需要的话也可以在客户端对小的资源聚集举办排列。

 

劳务版本管理

   坦率地讲,一说到版本就会令人认为很勤奋,很劳顿,不太容易,甚至会令人觉得难受——因为这会追加API的复杂度,并还要可能会对客户端爆发部分震慑。因而,在API的宏图中要尽量制止三个不等的本子。

  不扶助版本,不将版本控制作为不佳的API设计的依赖。假使您在APIs的宏图中引入版本,那迟早都会让你抓狂。由于再次来到的数据经过JSON来显现,客户端会由于不同的本子而接受到不同的性质。这样就会设有部分题材,如从内容我和认证规则方面改变了一个已存在的属性的含义。

  当然,我们不能幸免API可能在一些时候需要变更重临数据的格式和内容,而这也将造成消费端的一些生成,我们应有避免举办部分要害的调动。将API举办版本化管理是防止这种重大转变的一种有效措施。

因而情节协商扶助版本管理

  以往,版本管理通过URI本身的版本号来形成,客户端在哀求的URI中标明要博得的资源的版本号。事实上,许多大商店如Twitter、Yammer、非死不可、Google等通常在她们的URI里使用版本号。甚至像WSO2这样的API管理工具也会在它的URLs中要求版本号。

  面向REST原则,版本管理技术迅速发展。因为它不带有HTTP规范中放置的header,也不辅助仅当一个新的资源或概念被引入时才应该添加新URI的意见——即版本不是表现格局的扭转。另一个不予的说辞是资源URI是不会随时间改变的,资源就是资源。

  URI应该能简单地分辨资源——而不是它的“形状”(状态)。另一个就是必须指定响应的格式(表征)。还有一些HTTP
headers:Accept 和 Content-Type。Accept
header允许客户端指定所企盼或能扶助的响应的媒体类型(一种或多种)。Content-Type
header可分别被客户端和劳务端用来指定请求或响应的数目格式。

  例如,要得到一个user的JSON格式的多少:

  #Request:

  GET http://api.example.com/users/12345
  Accept: application/json; version=1

  #Response:

  HTTP/1.1 200 OK
  Content-Type: application/json; version=1

  {"id":"12345", "name":"Joe DiMaggio"}

  现在,大家对同样资源请求版本2的数据:

  #Request:

  GET http://api.example.com/users/12345
  Accept: application/json; version=2

  #Response:

  HTTP/1.1 200 OK
  Content-Type: application/json; version=2

  {"id":"12345", "firstName":"Joe", "lastName":"DiMaggio"}

  Accept
header被用来代表所期待的响应格式(以及示例中的版本号),注意上述四个一样的URI是如何是好到在不同的版本中分辨资源的。或者,假设客户端需要一个XML格式的数量,可以将Accept
header设置为"application/xml",如若需要的话也得以带一个点名的版本号。

  由于Accept
header能够被设置为允许多种媒体类型,在响应请求时,服务器将把响应的Content-Type
header设置为最匹配客户端请求内容的体系。更多音讯方可参考http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.Html

  例如:

  #Request

  GET http://api.example.com/users/12345

  Accept: application/json; version=1, application/xml; version=1

  上述呼吁中,假如服务器协理JSON
和XML格式的伏乞,或者二种都襄助,那么将由服务器来决定最后回到哪序列型的数量。但无论是服务器拔取哪种,都会在响应中蕴含Content-Type
header。

  例如,假设服务器再次回到application/xml格式的多少,结果是:

  #Response

  HTTP/1.1 200 OK
  Content-Type: application/xml; version=1

  <user>
    <id>12345</id>
    <name>Joe DiMaggio</name>
  </user>

  为了求证Content-Type在发送数据给服务器时的用途,那里给出一个用JSON格式创立新用户的事例:

  #Request

  POST http://api.example.com/users
  Content-Type: application/json;version=1

  {"name":"Marco Polo"}

  或者,调用版本2的接口:

  #Request

  POST http://api.example.com/users
  Content-Type: application/json;version=2

  {"firstName":"Marco", "lastName":"Polo"}

当没有点名版本时,重回什么版本?

  并不需要在每一个伸手中都指定版本号。由于HTTP
content-negotiation(内容协商)坚守类型的“最佳匹配”情势,所以您的API也应当遵照这一点。遵照这一原则,当客户端从未点名版本时,API应当重回所扶助的最早版本。

  仍旧这个事例,获取一个user的JSON格式的数目:

  #Request

  GET http://api.example.com/users/12345
  Accept: application/json

  #Response

  HTTP/1.1 200 OK
  Content-Type: application/json; version=1

  {"id":"12345", "name":"Joe DiMaggio"}

  相应地,当以POST模式向服务器发送数据时,假设服务器襄助六个例外版本,而请求时又从不点名版本,和方面的例子一样——服务器会将小小/最早版本的数码包含在body中。为了拓展求证,下面的事例以JSON格式请求一个蕴含多版本资源的服务器,来成立一个新用户(预期会重回版本1):

  #Request

  POST http://api.example.com/users
  Content-Type: application/json

  {"name":"Marco Polo"}

  #Response

  HTTP/1.1 201 OK
  Content-Type: application/json; version=1
  Location: http://api.example.com/users/12345

  {"id":"12345", "name":"Marco Polo"}

呼吁不帮助的版本

  当呼吁一个不襄助的版本号时(包含在API生命周期中一度破灭的资源版本),API应当再次回到一个荒谬的HTTP状态码406(表示不被接受)。此外,API还应当再次回到一个富含Content-Type:
application/json的响应体,其中含有一个JSON数组,用于阐明该服务器扶助的花色。

  #Request

  GET http://api.example.com/users/12345
  Content-Type: application/json; version=999

  #Response

  HTTP/1.1 406 NOT ACCEPTABLE 

  Content-Type: application/json

  ["application/json; version=1", "application/json; version=2",
"application/xml; version=1", "application/xml; version=2"]

怎么时候理应创立一个新本子?

  API开发中的很多地点都会打破约定,并最后对客户端爆发部分不良影响。倘诺你不确定API的修改会带动哪些的结局,保险起见最好考虑采用版本控制。当您在设想提供一个新本子是否合宜时,或者考虑对现有的回来表征举办改动是否必然能满意急需并被客户端所接受时,有如此多少个因素要考虑。

破坏性的改动

  • 改变属性名(例如将"name"改成"firstName")
  • 去除属性
  • 更改属性的数据类型(例如将numeric变为string,
    boolean变为bit/numeric,string 变为 datetime等等)
  • 变更验证规则
  • 在Atom样式的链接中,修改"rel"的值
  • 在现有的工作流中引入必要资源
  • 变更资源的定义/意图;概念/意图或资源情况的意思不同于它原有的意思。例如:
    • 一个content
      type是text/html的资源,以前表示的是所有辅助的传媒类型的一个"links"集合,而新的text/html则代表的是用户输入的“web浏览器表单”。
    • 一个包含"end提姆(Tim)e"参数的API,对资源"…/users/{id}/exams/{id}"表达的含义是学员在异常时间付诸试卷,而新的意义则是考试的预定完毕时间。
  • 因此充分新的字段来改变现有的资源。将五个资源统一为一个并弃用原始的资源。
    • 有诸如此类五个资源"…/users/{id}/dropboxBaskets/{id}/messages/{id}"和"…/users/{id}/dropboxBaskets/{id}/messages/{id}/readStatus"。新要求是把readStatus资源的习性放到单独的message资源中,并弃用readStatus资源。这将招致messages资源中指向readStatus资源的链接被移除。

  即便下边列出的并不健全,但它交给了部分会对客户端爆发破坏性影响的变型类型,这时急需考虑提供一个新资源或新本子。

非破坏性的改动

  • 在回来的JSON中添加新属性
  • 增长指向任何资源的"link"
  • 添加content-type补助的新格式
  • 添加content-language补助的新格式
  • 是因为API的奠基人和买主都要拍卖不同的casing,由此casing的浮动无关首要

版本控制应在什么级别出现?

  提出对单个的资源开展版本控制。对API的有的变动,如修改工作流,也许要跨四个资源的版本控制,以此来防范对客户端爆发破坏性的震慑。

使用Content-Location来增强响应

  可选。见RDF(Resource Description Framework,即资源描述框架)规范。

带有Content-Type的链接

  Atom风格的链接匡助"type"属性。提供充裕的消息以便客户端可以对特定的本子和情节类型举行调用。

找出辅助的本子

本身应当同时匡助几个版本?

  维护多少个不等的本子会让劳作变得繁琐、复杂、容易出错,而且代价高,对于此外给定的资源,你应有帮忙不抢先2个版本。

弃用

  Deprecated(弃用)的目的是用来证实资源对API依旧可用,但在将来会不设有并变得不可用。只顾:弃用的时长将由弃用政策决定——这里并不曾交给定义。

本身什么告知客户端被弃用的资源?

  许多客户端以后访问的资源可能在新本子引入后会被遗弃掉,由此,他们需要有一种格局来发现和督察他们的应用程序对弃用资源的应用。当呼吁一个弃用资源时,API应该正常响应,并带有一个布尔类型的自定义Header
"Deprecated"。以下用一个例证来举行验证。

  #Request

  GET http://api.example.com/users/12345
  Accept: application/json
  Content-Type: application/json; version=1

  #Response

  HTTP/1.1 200 OK
  Content-Type: application/json; version=1
  Deprecated: true
  {“id”:”12345”, “name”:”Joe DiMaggio”}

 

日期/时间拍卖

  假如没有妥善地、一致地拍卖好日期和岁月的话,那将变为一个大麻烦。我们经常会遇上时区的题目,而且由于日期在JSON中是以字符串的格式存在的,借使未指定统一的格式,那么解析日期也会是一个题目。

  在接口内部,服务端应该以UTC或GMT时间来囤积、处理和缓存时间戳。这将有效缓解日期和时间的题材。

Body内容中的日期/时间连串化

  有一个简易的措施可以化解这几个问题——在字符串中一直用相同的格式,包括时间片(带有时区音讯)。ISO8601时间格式是一个不利的化解方案,它应用了截然增强的时间格式,包括时辰、分钟、秒以及秒的小数部分(例如yyyy-MM-dd'T'HH:mm:ss.SSS'Z')。提出在REST服务的body内容中(请求和响应均包括)使用ISO8601代表所有的日期格式。

  顺便提一下,对于那几个基于JAVA的服务以来,Date艾达(Ada)pterJ库使用DateAdapter,Iso8601提姆(Tim)epoint艾达pter和HttpHeader提姆(Tim)estamp艾达pter类可以非凡容易地解析和格式化ISO8601日期和时间,以及HTTP
1.1
header(RFC1123)格式。可以从https://github.com/tfredrich/DateAdapterJ下载。

  对于这一个创造基于浏览器的用户界面来说,ECMAScript5业内一起始就隐含了JavaScript解析和开创ISO8601日期的情节,所以它应当改成我们所说的主流浏览器所服从的艺术。当然,即便你要补助这些不可能自动解析日期的旧版浏览器,可以采纳JavaStript库或正则表明式。这里有多少个可以分析和开创ISO8601时间的JavaStript库:

  http://momentjs.com/

  http://www.datejs.com/

HTTP Headers中的日期/时间序列化

  但是上述提出仅适用于HTTP请求或响应内容中的JSON和XML内容,HTTP规范针对HTTP
headers使用另一种不同的格式。在被RFC1123更替的RFC822中提出,该格式包括了各样日期、时间和date-time格式。不过,提出始终使用时间戳格式,在你的request
headers中它看起来像这样:

  Sun, 06 Nov 1994 08:49:37 GMT

  但是,这种格式没有设想毫秒或者秒的十进制小数。Java的SimpleDataFormat的格式串是:"EEE,
dd MMM yyyy HH:mm:ss 'GMT'"。

 

保安服务的安全

  Authentication(身份验证)指的是确认给定的央求是从服务已知的某人(或某个系统)发出的,且请求者是他协调所阐明的特别人。Authentication是为着求证请求者的真正身份,而authorization(授权)是为着声明请求者有权力去履行被呼吁的操作。

  本质上,这多少个过程是这般的:

  1. 客户端发起一个伸手,将authentication的token(身份阐明令牌)包含在X-Authentication
    header中,或者将token叠加在呼吁的查询串参数中。
  2. 服务器对authorization
    token(授权令牌)举行反省,并展开求证(有效且未过期),并基于令牌内容分析或者加载认证大旨。
  3. 服务器调用授权服务,提供注脚主题、被呼吁资源和必备的操作许可。
  4. 设若授权通过了,服务器将会连续健康运作。

  上边第三步的开发可能会相比较大,不过假若假设存在一个可缓存的权限决定列表(ACL),那么在发出远程请求前,可以在本地创立一个授权客户端来缓存最新的ACLs。

身份验证

  近日最好的做法是行使OAuth身份验证。强烈推荐OAuth2,然而它依旧处于草案情形。或者选用OAuth1,它完全可以胜任。在某些处境下也足以采用3-Legged
OAuth。更多关于OAuth的标准能够查看这里http://oauth.net/documentation/spec/

  OpenID是一个外加采用。然则提出将OpenID作为一个附加的身份验证选项,以OAuth为主。更多关于OpenID的业内能够查阅这里http://openid.net/developers/specs/

传输安全

  所有的证实都应该运用SSL。OAuth2需要授权服务器和access
token(访问令牌)来接纳TLS(安全传输层协议)。

  在HTTP和HTTPS之间切换会带来安全隐患,最好的做法是具备简报默认都接纳TLS。

授权

  对服务的授权和对其他应用程序的授权一样,没有其余区别。它遵照这样一个题材:“主体是不是对给定的资源有请求的许可?”这里给出了简单的三项数据(主体,资源和许可),由此很容易构造一个支撑那种概念的授权服务。其中重点是被给予资源访问许可的人或系统。使用这多少个相似概念,就足以为每一个主旨构建一个缓存访问控制列表(ALC)。

应用程序安全

  对RESTful服务以来,开发一个安全的web应用适用同样的标准。

  • 在服务器上表明所有输入。接受“已知”的不利的输入并拒绝错误的输入。
  • 防止SQL和NoSQL注入。
  • 接纳library如微软的Anti-XSS或OWASP的AntiSammy来对输出的数据开展编码。
  • 将音讯的长短限制在确定的字段长度内。
  • 服务应该只体现一般的错误新闻。
  • 考虑工作逻辑攻击。例如,攻击者可以跳过多步骤的订货流程来预订产品而无需输入信用卡音信呢?
  • 对可疑的移位记录日志。

  RESTful安全需要留意的地方:

  • 表明数据的JSON和XML格式。
  • HTTP动词应该被界定在同意的章程中。例如,GET请求无法去除一个实体。GET用来读取实体而DELETE用来删除实体。
  • 专注race
    conditions(竞争条件——由于六个或者四个经过竞争使用无法被同时做客的资源,使得那一个过程有可能因为日子上助长的次第原由此产出问题)。

  API网关可用于监视、限制和控制对API的拜会。以下内容可由网关或RESTful服务实现。

  • 蹲点API的拔取状态,并打听怎么活动是正常的,哪些是非正常的。
  • 界定API的接纳,使恶意用户不可以停掉一个API服务(DOS攻击),并且有能力阻止恶意的IP地址。
  • 将API密钥存储在加密的安全密钥库中。

 

缓存和可伸缩性

  通过在系统层级消除通过中距离调用来拿到请求的数码,缓存提升了系统的可扩展性。服务通过在响应中设置headers来增强缓存的力量。遗憾的是,HTTP
1.0中与缓存相关的headers与HTTP
1.1例外,因而服务器要同时帮忙二种版本。下表给出了GET请求要扶助缓存所不可不的最少headers集合,并付诸了适龄的叙述。

HTTP Header

描述

示例

Date

响应再次回到的日期和时间(RFC1123格式)。

Date: Sun, 06 Nov 1994 08:49:37 GMT

Cache-Control

响应可被缓存的最大秒数(最大age值)。如果响应不匡助缓存,值为no-cache。

Cache-Control: 360

Cache-Control: no-cache

Expires

假设给出了最大age值,该时间戳(RFC1123格式)表示的是响应过期的流年,也就是Date(例如当明日子)加上最大age值。假使响应不帮忙缓存,该headers不存在。

Expires: Sun, 06 Nov 1994 08:49:37 GMT

Pragma

当Cache-Control为no-cache时,该header的值也被装置为no-cahche。否则,不设有。

Pragma: no-cache

Last-Modified

资源本身最后被修改的日子戳(RFC1123格式)。

Last-Modified: Sun, 06 Nov1994 08:49:37 GMT

  为了简化,这里举一个响应中的headers集合的例子。这是一个简短的对资源拓展GET请求的响应,缓存时长为一天(24钟头):

  Cache-Control: 86400
  Date: Wed, 29 Feb 2012 23:01:10 GMT
  Last-Modified: Mon, 28 Feb 2011 13:10:14 GMT
  Expires: Thu, 01 Mar 2012 23:01:10 GMT

  下边是一个像样的例证,可是缓存被完全禁用:

  Cache-Control: no-cache
  Pragma: no-cache

ETag Header

  ETag
header对于注明缓存数据的新旧程度很有用,同时也助长条件的读取和翻新操作(分别为GET和PUT)。它的值是一个任意字符串,用来表示回到数据的本子。不过,对于再次来到数据的两样格式,它也得以不同——JSON格式响应的ETag与同一资源XML格式响应的ETag会不同。ETag
header的值可以像带有格式的底层域对象的哈希表(例如Java中的Obeject.hashcode())一样简单。提议为每个GET(读)操作重临一个ETag
header。其余,确保用双引号包含ETag的值,例如:

  ETag: "686897696a7c876b7e"

 

HTTP状态码(前10)

  以下是由RESTful服务或API再次来到的最常用的HTTP状态码,以及一些有关它们普遍用法的大概表明。另外HTTP状态码不太平日应用,它们仍然更出格,要么更尖端。大多数劳动套件只帮忙这些常用的状态码,甚至只援助其中的一有些,并且它们都能正常干活。

  200 (OK) —— 平时的功成名就景色。表示成功的最常见代码。

  201 (CREATED) ——(通过POST或PUT)创设成功。通过安装Location
header来含有一个针对性最新创设的资源的链接。

  204 (NO CONTENT)
—— 封装过的响应没有应用,或body中从不此外内容时(如DELETE),使用该意况。

  304 (NOT MODIFIED)
—— 用于有规则的GET调用的响应,以调减带宽的采用。
假诺拔取这一场馆,那么必须为GET调用设置Date、Content-Location和ETag
headers。不带有响应体。

  400 (BAD REQUEST)
—— 用于实践请求时或者引起无效状态的相似错误代码。如域名无效错误、数据丢失等。

  401 (UNAUTHORIZED)
—— 用于缺少认证token或证实token无效的错误代码。

  403 (FORBIDDEN)
—— 未授权的用户执行操作,没有权力访问资源,或者是因为某些原因资源不可用(如时间限制等),使用该错误码。

  404 (NOT FOUND)
—— 无论资源存不设有,无论是否有401、403的界定,当呼吁的资源找不到时,出于安全因素考虑,服务器都可以利用该错误码来掩盖。

  409 (CONFLICT)
—— 每当执行请求可能会滋生资源争执时选拔。例如,存在重复的实体,当不匡助级联删除时去除根对象。

  500 (INTERNAL SERVER ERROR)
—— 当服务器抛出相当时,捕捉到的形似错误。

 

外加资源

书籍

  REST API Design Rulebook,Mark Masse, 2011, O’Reilly Media, Inc.

  RESTful Web Services, Leonard Richardson and Sam Ruby, 2008,
O’Reilly Media, Inc.

*  RESTful Web Services Cookbook, Subbu Allamaraju, 2010, O’Reilly
Media, Inc.*

  REST in Practice: Hypermedia and Systems Architecture, Jim Webber,
et al., 2010, O’Reilly Media, Inc.

宗教,  APIs: A Strategy Guide, Daniel Jacobson; Greg Brail; Dan Woods,
2011, O’Reilly Media, Inc.

网站

  http://www.restapitutorial.com
http://www.toddfredrich.com

  http://www.ics.uci.edu/~fielding/pubs/dissertation/rest_arch_style.htm
  http://www.json.org/
https://github.com/tfredrich/DateAdapterJ

  http://openid.net/developers/specs/
  http://oauth.net/documentation/spec/
  http://www.json.org/JSONRequest.html
http://labs.omniti.com/labs/jsend

  http://enable-cors.org/
  http://www.odata.org/documentation/uri-conventions#FilterSystemQueryOption
  http://roy.gbiv.com/untangled/2008/rest-apis-must-be-hypertext-driven
  https://developer.linkedin.com/apis
  http://developers.facebook.com/docs/reference/api/
  https://dev.twitter.com/docs/api
http://momentjs.com/

  http://www.datejs.com/

 

在原翻译的基础上通过修改:http://blog.csdn.net/huayuqa/article/details/62237010

英文原文下载:RESTful Best Practices-v1
2.pdf

相关文章

Comment ()
评论是一种美德,说点什么吧,否则我会恨你的。。。