Restful API是目前比较成熟的一套互联网应用程序的API设计理念,Rest是一组架构约束条件和原则,符合Rest约束条件和原则的架构,我们就称为Restful架构,Restful架构具有结构清晰、符合标准、易于理解以及扩展方便等特点,受到越来越多网站的采用!
目录
1.背景
网站开发,完全可以采用软件开发的模式。但是传统上,软件和网络是两个不同的领域,很少有交集;软件开发主要针对单机环境,网络则主要研究系统之间的通信。互联网的兴起,使得这两个领域开始融合,现在我们必须考虑,如何开发在互联网环境中使用的软件。
RESTful架构,就是目前最流行的一种互联网软件架构。它结构清晰、符合标准、易于理解、扩展方便,所以正得到越来越多网站的采用。
但是,到底什么是RESTful架构,并不是一个容易说清楚的问题。下面,我就谈谈我理解的RESTful架构。
REST这个词,是Roy Thomas Fielding在他2000年的博士论文中提出的。Fielding是一个非常重要的人,他是HTTP协议(1.0版和1.1版)的主要设计者、Apache服务器软件的作者之一、Apache基金会的第一任主席。所以,他的这篇论文一经发表,就引起了关注,并且立即对互联网开发产生了深远的影响。
2. 基本概念
Fielding将他对互联网软件的架构原则,定名为REST,即Representational State Transfer的缩写。我对这个词组的翻译是"表现层状态转化"。如果一个架构符合REST原则,就称它为RESTful架构。
要理解RESTful架构,最好的方法就是去理解Representational State Transfer这个词组到底是什么意思,它的每一个词代表了什么涵义。如果你把这个名称搞懂了,也就不难体会REST是一种什么样的设计。
2.1 资源(Resources)
REST的名称"表现层状态转化"中,省略了主语。"表现层"其实指的是"资源"(Resources)的"表现层"。
所谓"资源",就是网络上的一个实体,或者说是网络上的一个具体信息。它可以是一段文本、一张图片、一首歌曲、一种服务,总之就是一个具体的实体。你可以用一个URI(统一资源定位符)指向它,每种资源对应一个特定的URI。要获取这个资源,访问它的URI就可以,因此URI就成了每一个资源的地址或独一无二的识别符。
所谓"上网",就是与互联网上一系列的"资源"互动,调用它的URI。
2.2 表现层(Representation)
"资源"是一种信息实体,它可以有多种外在表现形式。我们把"资源"具体呈现出来的形式,叫做它的"表现层"(Representation)。
比如,文本可以用txt格式表现,也可以用HTML格式、XML格式、JSON格式表现,甚至可以采用二进制格式;图片可以用JPG格式表现,也可以用PNG格式表现。
URI只代表资源的实体,不代表它的形式。严格地说,有些网址最后的".html"后缀名是不必要的,因为这个后缀名表示格式,属于"表现层"范畴,而URI应该只代表"资源"的位置。它的具体表现形式,应该在HTTP请求的头信息中用Accept和Content-Type字段指定,这两个字段才是对"表现层"的描。
2.3 状态转化(State Transfer)
访问一个网站,就代表了客户端和服务器的一个互动过程。在这个过程中,势必涉及到数据和状态的变化。
互联网通信协议HTTP协议,是一个无状态协议。这意味着,所有的状态都保存在服务器端。因此,如果客户端想要操作服务器,必须通过某种手段,让服务器端发生"状态转化"(State Transfer)。而这种转化是建立在表现层之上的,所以就是"表现层状态转化"。
客户端用到的手段,只能是HTTP协议。具体来说,就是HTTP协议里面,四个表示操作方式的动词:GET、POST、PUT、DELETE。它们分别对应四种基本操作:GET用来获取资源,POST用来新建资源(也可以用于更新资源),PUT用来更新资源,DELETE用来删除资源。
2.4 概念总结
综合上面的解释,我们总结一下什么是RESTful架构:
(1)每一个URI代表一种资源;
(2)客户端和服务器之间,传递这种资源的某种表现层(Representation);
(3)客户端通过四个HTTP动词,对服务器端资源进行操作,实现"表现层状态转化"。
3.Rest设计原则
3.1 每一个URI代表一种资源
一个URI只代表一种类型的资源。
http://xxx.com/api/users; // 获取所有用户信息 http://xxx.com/api/teachers; // 获取所有老师信息 http://xxx.com/api/areas; // 获取所有区域信息
3.2 同一种资源有多种表现形式
一种资源可以用多种格式(xml、json等)返回,客户端请求的时候,我们可以在请求头中设置参数,要求restful返回指定类型的数据,这是RESTful接口需要满足的元原则;
Accept:application/xml 请求时设置返回形式是xml,如使用ajax请求,则需要设置contentType:application/xml Accept:application/json 请求时设置返回形式是json,如使用ajax请求,则需要设置contentType:application/json
3.3 所有的操作都是无状态的
http请求本身是无状态的,而RESTful是建立在无状态http协议基础上的;所以本身RESTful的各种请求也是无状态的。
可以这么理解:协议对于事务处理没有记忆能力。缺少状态意味着如果后续处理需要前面的信息,则它必须重传,这样可能导致每次连接传送的数据量增大。但另一方面,在服务器不需要先前信息时它的应答就较快。
举个例子,当浏览器发送请求给服务器的时候,服务器响应,但是同一个浏览器再发送请求给服务器的时候,他会响应,但是他不知道你就是刚才那个浏览器,简单地说,就是服务器不会去记得你;
所以如果需要有状态之类的记忆功能,就借助浏览器的cookie、session及token技术去实现即可
3.4 规范统一接口
Rest接口约束定义为:
-
资源识别:它表示通过uri表示出要操作的资源,这里不能包含表示操作的动词;
-
请求动作:通过请求动作(http method)标识要执行的操作;
-
响应信息;:通过返回的状态码来表示这次请求的执行结果;
达不到RESTful接口规范的普通接口:
- http://xxx.com/api/getallUsers; // GET请求方式,获取所有的用户信息
- http://xxx.com/api/getuser/1; // GET请求方式,获取标识为1的用户信息
- http://xxx.com/api/user/delete/1 // GET、POST 删除标识为1的用户信息
- http://xxx.com/api/updateUser/1 // POST请求方式 更新标识为1的用户信息
- http://xxx.com/api/User/add // POST请求方式,添加新的用户
标准统一的RESTful风格接口规范:
- http://xxx.com/api/users; // GET请求方式 获取所有用户信息
- http://xxx.com/api/users/1; // GET请求方式 获取标识为1的用户信息
- http://xxx.com/api/users/1; // DELETE请求方式 删除标识为1的用户信息
- http://xxx.com/api/users/1; // PATCH请求方式,更新标识为1的用户部分信息
- http://xxx.com/api/users; // POST请求方式 添加新的用户
3.5 返回一致的数据格式
返回的数据格式,最起码有我们标准要求的几个字段,比如状态、code、信息、data等。
3.6 可缓存(客户端可以缓存响应的内容)
现在接口基本都提供了可缓存的功能,也就是说在接口开发阶段,我们会设置浏览器是否可以缓存,以及缓存的类型和有效时间等等.比如强缓存、协商缓存规范都是服务器端设置的。
4. API接口设计规范
4.1 URI规范
-
URL 的命名 必须 全部小写
-
URL 中资源( resource)的命名 必须 是名词,并且 必须 是复数形式
-
必须 优先使用 Restful 类型的 URL
-
URL 中不能出现 -, 必须 用下划线 _ 代替
-
URL 必须 是易读的
-
URL 一定不可 暴露服务器架构
http://xxx.com/api/male_users // 获取男性用户。
http://xxx.com/api/male_users&sort=age_desc // 获取年纪降序的男性用户.
-
避免多级URI
常见的情况是,资源需要多级分类,因此很容易写出多级的 URL,比如获取某个作者的某一类文章。
# GET /authors/12/categories/2
这种 URL 不利于扩展,语义也不明确,往往要想一会,才能明白含义。
更好的做法是,除了第一级,其他级别都用查询字符串表达。
# GET /authors/12?categories=2
4.2 请求方式
-
GET (SELECT): 查询;从服务器取出资源.POST(CREATE): 新增; 在服务器上新建一个资源;
-
POST(CREATE):在服务器新建一个资源;
-
PUT(UPDATE): 更新; 在服务器上更新资源(客户端提供改变后的完整资源);
-
PATCH(UPDATE): 更新;在服务器上更新部分资源(客户端提供改变的属性) ;
-
DELETE(DELETE): 删除; 从服务器上删除资源;
-
HEAD:获取资源的元数据;
-
OPTIONS:获取信息,关于资源的哪些属性是客户端可以改变的。
4.3 过滤信息
如果记录数量很多,服务器不可能都将它们返回给用户,API会提供参数,过滤返回结果,常见的参数有:
-
?limit=20:指定返回记录的数量为20;
-
?offset=8:指定返回记录的开始位置为8;
-
?page=1&per_page=50:指定第1页,以及每页的记录数为50;
-
?sortby=name&order=asc:指定返回结果按照name属性进行升序排序;
-
?animal_type_id=2:指定筛选条件。
4.4 状态码
下表列举了常见的 HTTP 状态码
状态码 | 描述 |
1xx | 代表请求已被接受,需要继续处理 |
2xx | 请求已成功,请求所希望的响应头或数据体将随此响应返回 |
3xx | 重定向 |
4xx | 客户端原因引起的错误 |
5xx | 服务端原因引起的错误 |
在 HTTP API 设计中,经常用到的状态码以及它们的具体说明如下表:
Status Code | 语义 | 说明 |
200 | OK | 请求已成功 |
201 | Created | 请求已完成,并导致了一个或者多个资源被创建,最常用在 POST 创建资源的时候 |
202 | Accepted | 请求已经接收并开始处理,但是处理还没有完成。一般用在异步处理的情况,响应 body 中应该告诉客户端去哪里查看任务的状态 |
204 | No Content | 请求已经处理完成,但是没有信息要返回,经常用在 PUT 更新资源的时候(客户端提供资源的所有属性,因此不需要服务端返回)。如果有重要的 metadata,可以放到头部返回 |
301 | Moved Permanently | 请求的资源已经永久性地移动到另外一个地方,后续所有的请求都应该直接访问新地址。服务端会把新地址写在Location头部字段,方便客户端使用。允许客户端把 POST 请求修改为 GET。 |
302 | Moved Temporarily | 临时重定向 |
304 | Not Modified | 请求的资源和之前的版本一样,没有发生改变。用来缓存资源,和条件性请求(conditional request)一起出现 |
307 | Temporary Redirect | 目标资源暂时性地移动到新的地址,客户端需要去新地址进行操作,但是不能修改请求的方法。 |
308 | Permanent Redirect | 和 301 类似,除了客户端不能修改原请求的方法 |
400 | Bad Request | 1.语义有误,当前请求无法被服务器理解; 2. 请求参数有误。 |
401 | Unauthorized | 当前请求需要身份验证。 |
403 | Forbidden | 服务器已经理解请求,但是拒绝执行它。与401响应不同的是,身份验证并不能提供任何帮助,而且这个请求也不应该被重复提交。如果这不是一个 HEAD 请求,而且服务器希望能够讲清楚为何请求不能被执行,那么就应该在实体内描述拒绝的原因。当然服务器也可以返回一个404响应,假如它不希望让客户端获得任何信息。 |
404 | Not Found | 请求失败,请求所希望得到的资源未被在服务器上发现。 |
405 | Method Not Allowed | 请求行中指定的请求方法不能被用于请求相应的资源。该响应必须返回一个Allow 头信息用以表示出当前资源能够接受的请求方法的列表。鉴于 PUT,DELETE 方法会对服务器上的资源进行写操作,因而绝大部分的网页服务器都不支持或者在默认配置下不允许上述请求方法,对于此类请求均会返回405错误。 |
406 | Not Acceptable | 请求的资源的内容特性无法满足请求头中的条件,因而无法生成响应实体。 |
409 | Conflict | 由于和被请求的资源的当前状态之间存在冲突,请求无法完成。 |
429 | Too Many Requests | 资源配额不足或达到速率限制。 |
499 | Client Closed Request | 请求被客户端取消。 |
500 | Internal Server Error | 服务器内部错误 |
501 | Not Implemented | 服务器不支持当前请求所需要的某个功能。当服务器无法识别请求的方法,并且无法支持其对任何资源的请求。 |
502 | Bad Gateway | 作为网关或者代理工作的服务器尝试执行请求时,从上游服务器接收到无效的响应。 |
503 | Service Unavailable | 由于临时的服务器维护或者过载,服务器当前无法处理请求。这个状况是临时的,并且将在一段时间以后恢复。 |
504 | Gateway Timeout | 作为网关或者代理工作的服务器尝试执行请求时,未能及时从上游服务器(URI标识出的服务器,例如HTTP、FTP、LDAP)或者辅助服务器(例如DNS)收到响应。 |
505 | HTTP Version Not Supported | 服务器不支持,或者拒绝支持在请求中使用的 HTTP 版本。 |
上面这些状态码覆盖了 API 设计中大部分的情况,如果对某个状态码不清楚或者希望查看更完整的列表,可以参考 HTTP Status Code。