想写这篇文章很久了,这是个大话题,不是一时半会就能说清楚的。 所以准备花个一星期整理资料,把思路理清楚,然后再在Team里做个sharing:)
其实RESTFul是架构风格,并不是实现规范,也不一定非要用HTTP,但鉴于HTTP的普世性和 SOA的实现基本都基于HTTP实现。 这句话只对了前一半, 实际上REST和HTTP是息息相关的,是一种Web架构,WWW是世界最大型的分布式应用,而其实现就是基于REST的web架构的设计标准,REST架构的提出者(Roy T. Fielding 2000年在他的博士论文中提出REST的架构风格),Roy 本身也是web标准(URI, HTTP, HTML) 的制定者,以及Web Server (Apache)的实现者,并且一直用REST的思想指导着标准制定,可以说HTTP就是该架构风格的一个典型应用,所以提到REST,就默认是用HTTP作为通信协议了。
一、HTTP 协议
2. Status Code
4. 中文扫盲
二、什么是REST
REST关键原则
三、REST开发指导
A very nice article of REST:
http://rest.elkstein.org/2008/02/what-is-rest.html
How to impl REST:
http://www.infoq.com/cn/articles/RESTSOAFuture
什么是好的RESTful API?
1. 这个API应该是对浏览器友好的,能够很好地融入web,而不是与web格格不入,好的RESTful API应该能够使用浏览器+HTML完成所有的测试。
2. API中所包含的资源和对资源的操作,应该是直观和容易理解的,并且符合HTTP协议的要求。
3.API应该是松耦合的。(有待进一步理解)
REST的耦合度比SOAP更低,因为SOAP实现仍是基于RPC调用方式,RPC方式是紧密耦合的表现;而紧密耦合的系统是无法适应Web级的规模可伸缩性的。REST Web服务则继承了Web松散耦合的特点,客户应用通过逻辑URL访问服务,服务的实现对客户来说是完全透明的,客户程序可以对服务的实现技术、方法毫无所知。
4.API中所有的格式应该是常见的通用格式,常见的有HTML、XML、JSON,常见的格式处理起来非常容易,有大量的框架和库提供支持。
5. 使用HTTP状态码来表达各种出错情况。如果一个所谓的”RESTful API“对任何请求都返回200 OK的响应,在响应的消息体中返回出错情况信息,这种做法显然不符合”确保操作语义的可见性“这个REST架构风格的基本要求。
6. 这个API应该对HTTP缓存是友好的
HTTP协议是个分层的架构,从两端的User agent(浏览器)到Origin server(Apache 服务器)之间,可以插入很多中间组件。在整个HTTP通信链条的很多位置,都可以设置缓存 。最常见的是浏览器缓存和服务器缓存:
浏览器端,下载一个类似HTTP watch的浏览器插件,就能很容易观察到对一个网站的进行第二次访问时,很多信息如图片,JS,JSS都是从浏览器缓存中取得,而不是去服务器取,节省了很多网络开销,也减轻了服务器压力。
在服务器端,也有很多缓存技术,可以参见这篇文章Caching your REST API来了解一种典型的服务器缓存技术,大概意思就是在对资源执行安全的操作如GET时,将response放入缓存,当对资源进行不安全操作如PUT/DELETE,将该response从缓存中移除(PURGE)出去,这样保证客户端不会得到过期的response。
在使用缓存时,不管是在客户端还是服务器端,一个非常重要的原则就是就语义透明性(Semantic Transparency)。
什么是缓存的语义透明性?就是不管在客户端还是服务器端使用缓存,对一个请求来说,其使用缓存得到的响应(Response)和直接访问服务器(Origin Server)所得到响应结果,应该是一模一样的,没有任何差别,缓存对服务的访问者来说应该是透明的。
完全达到语义透明性只是一个理想状态,Web是松耦合的,所以弱一致性(Weak consistency) 是基于Web的分布式应用的特点,但是我们可以通过一些手段来增强一致性,尽量达到语义透明性。常用的方式有失效、验证、过期。
如何对RESTful API进行版本控制?
一个比较简单实用的做法是直接在URI中插入版本号,这样做允许多个版本的API并行运行。另一个做法是在HTTP请求中加入自定义头信息,标明使用的版本号。不过这个做法其实对浏览器不够友好,简单地使用浏览器+HTML无法测试。
还有对于微小改动,最好可以做到向后兼容而不改变版本号,最关键的就是在扩展时不能破坏现有的客户端,例如,变更一个参数,可以选择同时兼容新旧两种输入,或者保持老参数不动,提供一个新参数,在文档中必须做出说明,不推荐新用户继续使用之前的参数。
HTTP1.1规范中给出的动词对于设计RESTful API 够用吗?
如果资源抽象做的很好,对于某个资源的任何操作,通常都能够映射到CRUD四个类别中。CRUD四个类别对于操作资源来说,绝大多数情况下是完备的。HTTP的四个方法对CRUD的映射关系是Create-POST, Retrieve-GET, Update-PUT, Delete-DELETE。如果在资源上定义的操作过多,往往这个资源可以拆分出更多的资源。
关于API的幂等性
幂等性是系统接口对外部调用的承诺,承诺只要调用接口成功,外部多次调用对系统影响是一致的。幂等性的好处是,外部在调用系统失败后,在进行重试时,无需更改请求内容。
在大规模分布式系统中,完成一个功能,需要很多服务或者组件的协作,通常我们会用一个uniqueRequestId or dedupeId 来标识一次请求的唯一性,而在调用服务出错时,如网络超时,系统内部错误,一般都要进行重试,幂等的接口允许重试时,使用相同的dedupeId。而非幂等的接口可能需要更改dedupeId来和上一次请求做区分,增加了客户端使用服务的负担。
所以在我看来,不仅GET/DELETE需要时幂等的,所有的REST API都应该尽量做到幂等,包括POST/PUT。比如在eLedger系统里,创建journal entry(流水账)是最常用的API,如果客户POST两次一模一样的请求(最主要是dedupeId一样),eLedger每次都会返回成功的结果,只不过在第二个POST到来时,系统检测到流水已经被创建,并不会创建新的流水,只是将已创建的结果返回给客户端,从某种意义上,减轻了客户使用eLedger服务的难度,因为其不用担心因为重复POST所造成的数据不一致。
关于REST的安全性
REST对安全性并没有像基于WSDL,SOAP的Web Service的WS-Security的安全规范,主要取决于REST service自己的实现,因为REST是架设在HTTP之上的,所以在底层通信(TCP)使用SSL是自然而然的,SSL基本可以解决中间人(man in middle) 和 重放攻击(replay attack)等安全问题,那么对于应用层,所要解决的就是认证(authentication),授权(authorization),访问(access)的问题了,鉴于可扩展性和开放性的考虑,使用OAuth是一个比较好的选择,首先OAuth是W3C的标准规范,提供了统一的标准和规范,降低了客户端的学习成本,其次是它把真个验证流程划分为认证、授权、访问三个步骤,不仅能满足传统的Client-Server验证,还具备非常良好的可扩展性,使得地方
如何定义Resource
REST开发又被称作“面向资源的开发”,这说明对于资源的抽象,是设计RESTful API的核心内容。RESTful API建模的过程与面向对象建模类似,是以名词为核心的。这些名词就是资源,任何可命名的抽象概念都可以定义为一个资源。而HTTP协议并不是一种传输协议,它实际提供了一个操作资源的统一接口。利用有限的几个方法(GET/POST/PUT/DELETE)来达到资源在不同表述状态(REpresentationalState)之间的转移(Transfer),这也是REST名称的由来。 所以RESTful API建模的过程,可以看作是具有统一接口约束的面向对象建模过程。
如果发现资源上的操作过多,以至于HTTP的方法不够用,应该考虑设计出更多的资源。设计出更多资源(以及相应的URI)对于RESTful API来说并没有什么害处。
五、REST 的成熟度模型(Maturity Model)
http://martinfowler.com/articles/richardsonMaturityModel.html