RESTful杂记
前言
在网上找了许久的关于REST的资料,发现网上大部分都是说的比较片面,虽然有部分说出了本质,但也没有详细提出,所以在这里记录一下。
RESTful是什么
首先,维基百科是这样说的:
表现层状态转换(REST,英文:Representational State Transfer)是Roy Thomas Fielding博士于2000年在他的博士论文中提出来的一种万维网软件架构风格,目的是便于不同软件/程序在网络(例如互联网)中互相传递信息
这样的概念有点难以理解,了解一个东西,通常可以先了解他的背景,他是为了解决什么问题而出现的?
Fielding是一个非常重要的人,他是HTTP协议(1.0版和1.1版)的主要设计者、Apache服务器软件的作者之一、Apache基金会的第一任主席。
而下面则是他在论文中提出REST的目的。
"本文研究计算机科学两大前沿----软件和网络----的交叉点。
长期以来,软件研究主要关注软件设计的分类、设计方法的演化,很少客观地评估不同的设计选择对系统行为的影响。
而相反地,网络研究主要关注系统之间通信行为的细节、如何改进特定通信机制的表现,常常忽视了一个事实,那就是改变应用程序的互动风格比改变互动协议,对整体表现有更大的影响。
我这篇文章的写作目的,就是想在符合架构原理的前提下,理解和评估以网络为基础的应用软件的架构设计,得到一个功能强、性能好、适宜通信的架构。"
这段话比较绕口,总结一下,就是REST是一个为了进一步解耦client和server的架构风格。
REST风格
首先,根据论文可以得知,REST风格是由约束来定义的
Web 架构背后的设计基本原理,能够被描述为由一组应用于架构中元素之上的约束组成
的架构风格。当将每个约束添加到进化中的风格时,会产生一些影响。通过检查这些影响,
我们就能够识别出 Web 的约束所导致的属性。然后就能够应用额外的约束来形成一种新的
架构风格,这种风格能够更好地反映出现代 Web 架构所期待的属性。
client-servet
client-server之间的解耦,服务提供者和服务消费者互不影响,也是我们常说的前后端分离。前后端分离的优势是比较显著的,改善了用户接口跨多个平台的可移植性;同时通过简化服务器组件,改善了系统的可伸缩性。
无状态
这个约束使架构拥有了可见性、可靠性和可伸缩性等三个架构属性。
可见性是指能单独的理解一个请求,可靠性是减轻了从局部故障中恢复的任务量, 可伸缩性是指为不必在多个请求之间保 存状态,从而允许服务器组件迅速释放资源。
可缓存
优势明显,不赘述。
统一接口
它强调组件之间要有 一个统一的接口。通过在组件接口上应用通用性的软件工程原则,整体的系统架 构得到了简化,交互的可见性(通过方法名即知道动作)也得到了改善。实现与它们所提供的服务是解耦的,这促进了独立的可进化性。
然而,付出的代价是,统一接口降低了效率,因为信息都使用标准化的形 式来转移,而不能使用特定于应用的需求的形式。(只能使用put post delete get patch等)
解决方法:为需要的动作增加一个 endpoint,使用 POST 来执行动作,比如 POST /resend 重新发送邮件。
分层系统
分层系统风格通过限制组件的行为(即,每个组件只 能“看到”与其交互的紧邻层),将架构分解为若干等级的层。通过将组件对系统的知识限 制在单一层内,为整个系统的复杂性设置了边界,并且提高了底层独立性。
我们能够使用层来封装遗留的服务,使新的服务免受遗留客户端的影响,通过将不常用的功能转移到一个共享的中间组件中,从而简化组件的实现。中间组件还能够通过支持跨多个网络和处理器的负 载均衡,来改善系统的可伸缩性。
也就是说服务器和客户端之间的中间层(代理,网关等)代替服务器对客户端的请求进行回应,而客户端不需要关心与它交互的组件之外的事情。
按需加载代码
通过下载并执行 applet 形式或脚本形式的代码,REST允许对客户端的功能进行扩展。通过减少必须被预先实现的功能的数目,简化了客户端的开发。允许在部署之后下载功能代 码也改善了系统的可扩展性。然而,这也降低了可见性,因此它只是REST的一个可选的约束。
设计原则(GITHUB API)
了解了REST是什么东西后,我们才能设计出合适的API,以下是根据GITHUB API来总结的(基本参考自:https://cizixs.com/2016/12/12...)
使用https
这个和 Restful API 本身没有很大的关系,但是对于增加网站的安全是非常重要的。
API地址和版本
如果 API 变化比较大,可以把 API 设计为子域名,比如 https://api.github.com/v3
响应内容
尽量使用JSON,JSON在多种语言中支持,如果需要使用其他的如XML, 应该在请求头部 Accept 中指定
以资源为中心
资源分为单个文档和集合,尽量使用复数来表示资源,单个资源通过添加id或者name等来表示。一个资源可以有多个不同的 URL。资源可以嵌套,通过类似目录路径的方式来表示,以体现它们之间的关系。
/users/:username/repos /users/:org/repos /repos/:owner/:repo /repos/:owner/:repo/tags /repos/:owner/:repo/branches/:branch
使用正确的METHOD
这个比较容易理解,即get(获取),post(创建),put(替换),patch(局部更新),delete(删除),head(获取某个资源的头部信息。比如只想了解某个文件的大小,某个资源的修改日期等)
对于不符合CURD的情况,可以采用参数协助
如分页page=2&per_page=100:指定第几页,以及每页的记录数,或者增加一个endpoint,如上面说的重发邮件,或者将动作转换为资源(Github:比如“喜欢”一个 gist,就增加一个 /gists/:id/star 子资源,然后对其进行操作:“喜欢”使用 PUT /gists/:id/star,“取消喜欢”使用 DELETE /gists/:id/star)
状态码
https://developer.mozilla.org...
- 2XX:请求正常处理并返回
- 3XX:重定向,请求的资源位置发生变化
- 4XX:客户端发送的请求有错误
- 5XX:服务器端错误
错误处理
返回错误时,在响应内容里加上具体的错误信息。
Hypermedia API
当服务端修改API时,客户端不需要知道和修改。
验证和授权, OAUTH2等
限流, 参考github
https://developer.github.com/...
对用户的请求限流之后,要有方法告诉用户它的请求使用情况,Github API 使用的三个相关的头部:
X-RateLimit-Limit: 用户每个小时允许发送请求的最大值 X-RateLimit-Remaining:当前时间窗口剩下的可用请求数目 X-RateLimit-Rest: 时间窗口重置的时候,到这个时间点可用的请求数量就会变成 X-RateLimit-Limit 的值
编写清晰的文档
REST与http的关系?
个人理解是REST是一种架构风格,而http则是这种架构实现下的一种协议。
比较(以操作为中心)
- 以操作为中心可见性低,即不够清晰。
- 在除了CURD的接口外,以操作为中心调用效率高,不需要hack。
- 以操作为中心没有HyperMidea Api,修改api效率低,需要客户端服务端同时修改。
- 以操作为中心上手难度系数大。
- 以资源为中心,简单数据操作,无事务处理,开发和调用简单, 以操作为中心,清晰的规范标准定义,能够处理较为复杂的面向活动的服务
在通常的软件开发过程中,我们常常需要分析达成某个目标所需要使用的业务逻辑,并为业务逻辑的执行提供一系列运行接口。在一些Web服务中,这些接口常常表达了某个动作,如将商品放入购物车,提交订单等。这一系列动作组合在一起就可以组成完成目标所需要执行的业务逻辑。在需要调用这些接口的时候,软件开发人员需要向这些接口所在的URL发送一个请求,从而驱使服务执行该动作