本文首要读者

引言

REST是什么

  联合接口

    遵照资源

    经过特色来操作资源

    自描述的音信

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

  无状态

  可缓存

  C-S架构

  分层系统

  按需编码(可选)

REST快速提醒

  运用HTTP动词表示一些含义

  客观的资源名

  XML和JSON

  始建适当粒度的资源

  设想连通性

定义

  幂等性

  安全

HTTP动词

  GET

  PUT

  POST

  PUT和POST的创立相比

  DELETE

资源命名

  资源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)Fielding在她的大学生杂谈中指出并定义了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是什么”一节中也波及过。

  依据Roy菲尔德(Field)ing在他的博客中的描述(http://roy.gbiv.com/untangled/2008/rest-apis-must-be-hypertextdriven),REST接口中最要紧的有些是超文本的应用。另外,他还指出,在付出任何有关的消息在此以前,一个API应该是可用和可领略的。也就是说,一个API应当可以透过其链接导航到数量的逐条部分。不指出只回去纯数据。

  可是当下的业界先驱们并从未平日采纳这种做法,这反映了HATEOAS仅仅在成熟度模型中的使用率更高。纵观众多的服务序列,它们基本上再次回到更多的数目,而回到的链接却很少(或者尚未)。这是违反菲尔德(Field)(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 not
found','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)。

  通过引入一组广泛的、公认的分隔符,用于过滤的表明式可以以相当直观的款型被接纳。用这一个分隔符来设置过滤查询参数的值,这些分隔符所创造的参数名/值对可以越来越便于地被服务端解析并增强多少查询的特性。近来已有些分隔符包括用来分隔每个过滤短语的竖线(”|”)和用来分隔参数名和值的双冒号(”::”)。那套分隔符丰盛唯一,并符合大多数情景,同时用它来构建的字符串查询参数也尤为容易精晓。下边将用一个简单易行的例子来介绍它的用法。假使大家想要给名为“托德”的用户们发送请求,他们住在加尔各答,有着“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、非死不可、谷歌等平时在他们的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提姆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的劳务以来,DateAdapterJ库使用DateAdapter,Iso8601提姆(Tim)epoint艾达(Ada)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的Anti萨姆my来对出口的数量举行编码。
  • 将音讯的长短限制在确定的字段长度内。
  • 服务应该只显示一般的错误信息。
  • 考虑工作逻辑攻击。例如,攻击者可以跳过多步骤的预购流程来预订产品而无需输入信用卡消息吗?
  • 对可疑的移动记录日志。

  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

相关文章

网站地图xml地图