RESTful Web API--设计风格
原文地址:http://www.cnblogs.com/artech/p/restful-web-api-02.html
RESTful背景介绍
2000年,Roy Thomas Fielding博士在他那篇著名的博士论文《Architectural Styles and the Design of Network-based Software Architectures》中提出了几种软件应用的架构风格,REST作为其中的一种架构风格在这篇论文的第5章中进行了概括性的介绍。
REST是“REpresentational State Transfer”的缩写,可以翻译成“表现状态转换”,但是在绝大多数场合中我们只说REST或者RESTful。
Fielding在论文中将REST定位为“分布式超媒体应用(Distributed Hypermedia System)”的架构风格,它在文中提到一个名为“HATEOAS(Hypermedia as the engine of application state)”的概念。
采用URI标识资源
SOAP Web API采用RPC风格,它采用面向功能的架构,所以我们在设计SOAP Web API的时候首相考虑的是应高提供怎样的功能(或者操作)。
RESTful Web API采用面向资源的架构,所以在设计之初首先需要考虑的是有哪些资源可供操作。
一个资源必须具有一个或者多个标识,既然我们设计的Web API,那么很自然地应该采用URI来作为资源的标识。
除了必要的标志性和可选的可读性之外,标识资源的URI应该具有“可寻址性(Addressability)”。
URI不仅仅指明了被标识资源所在的位置,而且通过这个URI可以直接获取目标资源。
使用“链接”关联相关的资源
在绝大多数情况下,资源并不会孤立地存在,必然与其它资源具有某种关联。
利用URL将资源关联在一起,就是一份超文本/超媒体文档,我们可以根据需要获取对应的资源,这也是爬虫的实现原理。
Fielding在他的论文中将REST定位为“分布式超媒体应用”的架构风格,而超媒体的核心就是利用“链接”相关的信息结成一个非线性的网,所以从一点也可以看出REST和“使用链接关联相关的资源”这个特性使吻合的。
使用统一的接口
能否采用统一接口是RESTful Web API和采用RPC风格的SOAP Web服务又一区别。
#RPC风格
1: public class RoleService 2: { 3: public IEnumerable<string> GetAllRoles(); 4: public void CreateRole(string roleName); 5: public void DeleteRole(string roleName);
6: public void AddRolesInUser(string userName, string[] roleNames); 7: public void RemoveRolesFromUser(string userName, string[] roleNames); 8: }
#RESTful 1: public class RolesService 2: { 3: public IEnumerable<string> Get(); 4: public void Create(string roleName); 5: public void Delete(string roleName); 6: } 7: 8: public class RoleAssignmentsService 9: { 10: public void Create(RoleAssignment roleName); 11: public void Delete(RoleAssignment roleName); 12: }
使用标准的HTTP方法
Web API分别针对CRUD的操作只能接受具有对应HTTP方法的请求.
GET、HEAD和OPTIONS这三个HTTP方法旨在发送请求以或者所需的信息。
OPTIONS请求旨在发送一种“探测”请求以确定针对某个目标地址的请求必须具有怎样的约束(比如应该采用怎样的HTTP方法以及自定义的请求报头),然后根据其约束发送真正的请求。
POST、PUT、PATCH和DELETE,它们旨在针对目标资源作添加、修改和删除操作。
通过发送POST和PUT请求均可以添加一个新的资源,但是两者的不同之处在于:
对于前者,请求着一般不能确定标识添加资源最终采用的URI,即服务端最终为成功添加的资源指定URI;
对于后者,最终标识添加资源的URI是可以由请求者控制的。
也正是因为这个原因,如果发送PUT请求,我们一般直接将标识添加资源的URI作为请求的URI;
对于POST请求来说,其URI一般是标识添加资源存放容器的URI。
安全性与幂等性
关于HTTP请求采用的这些个方法,具有两个基本的特性,即“安全性”和“幂等性”。
GET、HEAD和OPTIONS均被认为是安全的方法,因为它们旨在实现对数据的获取,并不具有“边界效应(Side Effect)”。
至于其它4个HTTP方法,由于它们会导致服务端资源的变化,所以被认为是不安全的方法。
幂等性(Idempotent)是一个数学上的概念,在这里表示发送一次和多次请求引起的边界效应是一致的。
上述3种安全的HTTP方法(GET、HEAD和OPTIONS)均是幂等方法。
对于PUT请求,只有在对应资源不存在的情况下服务器才会进行添加操作,否则只作修改操作,所以它也是幂等方法。
至于最后一种POST,由于它总是进行添加操作,如果服务器接收到两次相同的POST操作,将导致两个相同的资源被创建,所以这是一个非幂等的方法。
当我们在设计Web API的时候,应该尽量根据请求HTTP方法的幂等型来决定处理的逻辑。
支持多种资源表示方式
资源和资源的表示(Representaion)是两个不同的概念,资源本身是一个抽象的概念,是看不见摸不着的,而看得见摸得着的是资源的表现。
对于Web来说,目前具有两种主流的数据结构,XML和JSON,它们也是资源的两种主要的呈现方式。
我们在设计Web API的时候,应该支持不同的资源表示,我们不能假定请求提供的资源一定表示成XML,也不能总是以JSON格式返回获取的资源,正确的做法是:根据请求携带的信息识别提交和希望返回的资源表示。
对于请求提交的资源,我们一般利用请求的Content-Type报头携带的媒体类型来判断其采用的表示类型。
对于响应资源表示类型的识别,可以采用如下两种方式:
1.让请求URI包含资源表示类型,这种方式使用的最多的是针对多语言的资源,我们一般讲表示语言(也可以包含地区)的代码作为URI的一部分,比如“http://www.artech.com/en/orders/2013”表示将2013年的订单以英文的形式返回。
2.采用“内容协商(Content Negotiation)”根据请求相关报头来判断它所希望的资源表示类型,比如“Accept”和“Accept-language”报头可以体现请求可以接受的响应媒体类型和语言。
无状态性
RESTful只要维护资源的状态,而不需要维护客户端的状态。
对于它来说,每次请求都是全新的,它只需要针对本次请求作相应的操作,不需要将本次请求的相关信息记录下来以便用于后续来自相同客户端请求的处理。
一般情况下,页面导航均具有“上一页”和“下一页”链接用于呈现当前页的前一页和后一页的记录。
那么现在有两种实现方式返回上下页的记录:
1.Web API不仅仅会定义根据具体页码的数据查询定义相关的操作,还会针对“上一页”和“下一页”这样的请求定义单独的操作。
它自身会根据客户端的Session ID对每次数据返回的页面在本地进行保存,以便能够知道上一页和下一页具体是哪一页。
2.Web API只会定义根据具体页码的数据查询定义相关的操作,当前返回数据的页码由客户端来维护。
第一种貌似很“智能”,其实就是一种画蛇添足的作法,因为它破坏了Web API的无状态性。
设计无状态的Web API不仅仅使Web API自身显得简单而精炼,还因减除了针对客户端的“亲和度(Affinty)”使我们可以有效地实施负载均衡,因为只有这样集群中的每一台服务器对于每个客户端才是等效的。