转自:https://www.cnblogs.com/imyalost/p/7923230.html
参考资料:
一、REST的由来
全称:REST,全称是Resource Representational State Transfer,即:资源在网络中以某种形式进行状态转移。————所谓状态的转移,可参考《HTTP权威指南》一书中对协议的详细解释,此处不过多赘述!
出现:REST最早是由Roy Fielding在2000年发表的博士论文中提到的,Roy Thomas Fielding是HTTP协议(v1.0和v1.1)的主要设计者、Apache服务器作者之一、Apache基金会第一任主席。
定义:简单来说REST是一种系统架构设计风格(而非标准),一种分布式系统的应用层解决方案。
背景:早期的网页端是前后台一起的,比如PHP、JSP等。而随着近几年移动端的快速发展和分布式架构的应用,各种Client层出不穷,这个时候就需要有个统一的机制,来为前后端通信提供服务。
RESTful API就是目前比较成熟的的一套应用程序API设计理论。
目的:Client和Server端进一步解耦。
应用:最为经典的莫过于github API。
二、RESTful的特征和优点
1、客户端-服务器(Client-Server):提供服务的服务器和使用服务的客户端分离解耦;
优点:提高客户端的便捷性(操作简单)
简化服务器提高可伸缩性(高性能、低成本)
允许客户端服务端分组优化,彼此不受影响
2、无状态(Stateless):来自客户的每一个请求必须包含服务器处理该请求所需的所有信息(请求信息唯一性);
优点:提高可见性(可以单独考虑每个请求)
提高可靠性(更容易故障恢复)
提高了可扩展性(降低了服务器资源使用)
其它理解:
解释1:http请求本身就是无状态的,基于C-S架构,客户端的每一次请求带有充分的信息能够让服务端识别。请求所需的一些信息都包含在URL的查询参数、header、div,服务端能够根据请求的各种参数,无需保存客户端的状态,将响应正确返回给客户端。无状态的特征大大提高的服务端的健壮性和可拓展性。
当然,这种无状态性的约束也是有缺点的,客户端的每一次请求都必须带上相同重复的信息确定自己的身份和状态,造成传输数据的冗余性,但这种确定对于性能和使用来说,几乎是忽略不计的。
解释2:所谓无状态即所有的资源都可以URI定位,而且这个定位与其他资源无关,也不会因为其他资源的变化而变化。Restful 是典型的基于
HTTP的协议,HTTP连接最显著的特点是客户端发送的每次请求都需要服务器回送响应,在请求结束后,会主动释放连接。从建立连接到关闭
连接的过程称为“一次连接”。前面一次请求与后面一次请求没有必然的联系,所以是无状态的。
3、可缓存(Cachable):服务器必须让客户端知道请求是否可以被缓存?如果可以,客户端可以重用之前的请求信息发送请求;
优点:减少交互连接数
减少连接过程的网络时延
其它理解:
在万维网上,客户端可以缓存页面的响应内容。因此响应都应隐式或显式的定义为可缓存的,若不可缓存则要避免客户端在多次请求后用旧数据或脏数据来响应。管理得当的缓存会部分地或完全地除去客户端和服务端之间的交互,进一步改善性能和延展性。
4、分层系统(Layered System):允许服务器和客户端之间的中间层(代理,网关等)代替服务器对客户端的请求进行回应,而客户端不需要关心与它交互的组件之外的事情;
优点:提高了系统的可扩展性
简化了系统的复杂性
5、统一接口(Uniform Interface):客户和服务器之间通信的方法必须是统一化的。(例如:GET,POST,PUT.DELETE)
优点:提高交互的可见性
鼓励单独优化改善组件
6、支持按需代码(Code-On-Demand,可选):服务器可以提供一些代码或者脚本并在客户的运行环境中执行。
优点:提高可扩展性
三、概要设计方法
1、协议
API与Client的通信协议,总是使用HTTPS协议。
PS:使用HTTPS协议和RESTful API本身没有多大关系,但是对于增加网站的安全是非常重要的,特别是如果提供的是公开的API,那么HTTPS久更显得重要了。
2、域名
应该尽量将API部署在专用的域名下面,比如:
https://api.github.com
如果API变化较大,可以把API设计为子域名,比如:
https://example.com/api/v1
3、版本(Versioning)
一般而言应该将API放入URL中,比如:
https://example.com/api/v1
还可以将版本号放入HTTP信息头中,但这样不如放入URL方便和直观。
4、路径(Endpoint)
在协议中,每个网址代表一种资源的存放地址,所以网址终不能有动词,只能有名词,而且名词一般都应该与数据库的表字段对应,且API中的名词应该使用复数。例如:
/users/:username/repos /users/:org/repos /repos/:owner/:repo /repos/:owner/:repo/tags /repos/:owner/:repo/branches/:branch
PS:根据RFC3986定义,URL是大小写敏感的,所以应该尽量使用小写字母来命名!
5、方法(Method)
有了资源的URL设计,所有针对资源的操作都是使用HTTP方法指定的,常见的方法有(括号中为对应的SQL命令):
Verd | 描述 |
HEAD(SELECT) | 只获取某个资源的头部信息 |
GET(SELECT) | 获取资源 |
POST(CREATE) | 创建资源 |
PATCH(UPDATE) | 更新资源的部分属性(很少用,一般用POST代替) |
PUT(UPDATE) | 更新资源,客户端需要提供新建资源的所有属性 |
DELETE(DELETE) | 删除资源 |
比如:
GET /user:列出所有的用户POST /user:新建一个用户PATCH /user/ID:更新某个指定用户的信息DELETE /user/ID:删除所有用户
6、数据过滤(Filtering)
如果数据量太大,服务器不可能将所有数据返回给用户。API应该提供参数(比如Query),过滤返回结果。比如:
?limit=10:指定返回记录的数量 ?offset=10:指定返回记录的开始位置 ?page=2&per_page=100:指定第几页,以及每页的记录数 ?sortby=name&order=asc:指定返回结果按照哪个属性排序,以及排序顺序 ?state=close:指定筛选条件
7、状态码
在HTTP报文构成中,有个字段很重要:status code。它说明请求的大致情况,是否正常处理、出现了什么错误等。状态码都是三位数,大概分为了一下几个区间:
状态码 | 描述 |
2XX | 请求正常处理并返回 |
3XX | 重定向,请求的资源位置发生变化 |
4XX | 客户端发送的请求有误 |
5XX | 服务器端的错误 |
关于状态码,具体的介绍可以去我之前的博客HTTP状态码或者参考其他资料,这里不过多赘述。
8、错误处理
如果出错的话,在response body中应通过message字段,以键值对的格式,给出明确的错误信息。
最基本的思路应该是:尽可能提供准确的错误信息,比如数据格式不正确、缺少某个字段......而不是直接说“请求错误”之类的信息。
9、Hypermedia API
Restful API的设计最好做到Hypermedia:即在返回结果中提供相关资源的链接,连向其他API方法,使用户不需要查文档也知道下一步做什么。
这样做的好处是,用户可以根据返回结果就能得到后续操作需要访问的地址。
10、身份验证
一般来说,让任何人随意访问公开的 API 是不好的做法,验证和授权是两件事情:
验证(Authentication):确定用户是其申明的身份,比如提供账户的密码。不然的话,任何人伪造成其他身份(比如其他用户或者管理员)是非常危险的;
授权(Authorization):保证用户有对请求资源特定操作的权限。比如用户的私人信息只能自己能访问,其他人无法看到;有些特殊的操作只能管理员可以操作,其他用户有只读的权限等。
如果没有通过验证,需要返回401 Unauthorized状态码,并在 body 中说明具体的错误信息;而没有被授权访问的资源操作,需要返回403 Forbidden状态码,还有详细的错误信息。
PS:Github API 对某些用户未被授权访问的资源操作返回404 Not Found,目的是为了防止私有资源的泄露(比如黑客可以自动化试探用户的私有资源,返回 403 的话,就等于告诉黑客用户有这些私有的资源)。
11、编写文档
API最终是给人使用的,无论是对内还是对外,即使遵循上面提到的所有规则,API设计的很优雅,但有时候用户还是不知道该如何使用这些提供的API。
因此,编写清晰可读的文档是很必要的事情。