本文首要读者

引言

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架构模式讲述了六种设计准则。这多少个用于架构的统筹准则,最早是由RoyFielding在她的学士随笔中提议并定义了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是什么”一节中也关系过。

  依据罗伊菲尔德(Field)(Field)ing在她的博客中的描述(http://roy.gbiv.com/untangled/2008/rest-apis-must-be-hypertextdriven),REST接口中最关键的一对是超文本的行使。此外,他还提议,在付给任何有关的新闻在此之前,一个API应该是可用和可了解的。也就是说,一个API应当能够经过其链接导航到多少的顺序部分。不提议只回去纯数据。

  不过当下的业界先驱们并没有日常应用那种做法,这反映了HATEOAS仅仅在成熟度模型中的使用率更高。纵观众多的服务体系,它们基本上重回更多的数码,而回到的链接却很少(或者没有)。这是违反Field(Field)ing的REST约定的。Fielding说:“新闻的每一个可寻址单元都指导一个地点……查询结果应当突显为一个富含摘要信息的链接清单,而不是目标数组。”

  另一方面,简单粗暴地将总体链接集合再次回到会大大影响网络带宽。在骨子里情况中,依照所需的标准化或行使状态,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)。

  通过引入一组广泛的、公认的分隔符,用于过滤的表达式可以以分外直观的形式被应用。用那么些分隔符来设置过滤查询参数的值,这么些分隔符所创立的参数名/值对可以更为便于地被服务端解析并增强数据查询的性质。近日已有些分隔符包括用来分隔每个过滤短语的竖线(”|”)和用来分隔参数名和值的双冒号(”::”)。这套分隔符丰富唯一,并符合大多数意况,同时用它来构建的字符串查询参数也愈发便于精晓。下边将用一个粗略的例子来介绍它的用法。假如大家想要给名为“托德(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的劳务以来,DateAdapterJ库使用Date艾达(Ada)pter,Iso8601提姆(Tim)epoint艾达pter和HttpHeader提姆estampAdapter类能够分外容易地分析和格式化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

  下边是一个接近的事例,然则缓存被全然禁用:

  json,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地图