现在的后端接口都是restful API模式较多,经常性的接触到这个词汇,今天就来仔细研究下它到底是什么意思把。
1.字面含义阐述:
REST:Representational State Transfer
,翻译是”表述性资源状态转化”。
2.理解RESTful
要理解RESTful架构,就要去理解Representational State Transfer这个词组的含义。
下面我们结合REST原则,围绕资源展开讨论,从资源的定义、获取、表述、关联、状态变迁等角度,列举一些关键概念并加以解释。
- 资源与URI
- 统一资源接口
- 资源的表述
- 资源的链接
状态的转移
2.1 什么是表述性资源与URI?
资源定义其实很宽泛,只要有被使用到的价值都可以叫做资源。比如说某个人的手机号码,或者说潜在的投资价值等。
在Web上我们主要讲的资源就是各种能够得到的数据,图片等信息。
如何让一个资源可以得到标识,就像我们每个人的身份证号码一样,根据身份证号码就可以得到一个人的基本信息?
在web上我们的标识就是
URI(Uniform Resource Identifier)
。URI既可以看成是资源的地址,也可以看成是资源的名称。URI的设计应该遵循可寻址性原则,具有自描述性,需要在形式上给人以直觉上的关联。
这里直接给出满足RESTful原则的url设计提倡:
https://xxx.com/api/v1/actionName
协议 / 网址 / 表示是api接口 / 接口版本 / 请求的api名字
2.2 什么是统一资源接口?
统一接口包含了一组受限的预定义的操作,不论什么样的资源,都是通过使用相同的接口进行资源的访问。简单来理解其实就是我们经常见到的HTTP方法:
- GET(SELECT):从服务器取出资源(一项或多项)。
- POST(CREATE):在服务器新建一个资源。
- PUT(UPDATE):在服务器更新资源(客户端提供改变后的完整资源)。
- PATCH(UPDATE):在服务器更新资源(客户端提供改变的属性)。
- DELETE(DELETE):从服务器删除资源。
我们通常都是使用get,post等方法进行请求接口。
2.3 什么是资源的表述?
资源的表述包括数据和描述数据的元数据,例如,HTTP头”Content-Type” 就是这样一个元数据属性。
那么客户端如何知道服务端提供哪种表述形式呢?
我们通常都是通过HTTP内容进行协商,客户端可以通过Accept头请求一种特定格式的表述,服务端则通过Content-Type告诉客户端资源的表述形式。
# Request GET https://api.github.com/orgs/github HTTP/1.1 Accept: application/json #Response HTTP/1.1 200 OK Content-Type:application/json;charset=utf-8 { "login":"github", "id":"1", "url":"https://api.github.com/orgs/github", "name":"github" ... }
2.4 什么是资源的链接?
当我们浏览Web网页时,从一个链接跳到一个页面,再从另一个链接跳到另外一个页面,就是利用了超媒体的概念:把一个个把资源链接起来.
要达到这个目的,就要求在表述格式里边加入链接来引导客户端。在《RESTful Web Services》一书中,作者把这种具有链接的特性成为连通性。下面我们看一个github的栗子。
```javascript # Request GET https://api.github.com/orgs/github HTTP/1.1 Accept: application/json #Response HTTP/1.1 200 OK Link:<https://api.github.com/orgs/github/repos?page=2>;rel="next", <https://api.github.com/orgs/github/repos?page=3>;rel="last", Content-Type:application/json;charset=utf-8 [ { "id":"1296296", "url":"https://api.github.com/orgs/github", "name":"github" ... } ]
我们注意到这个栗子里面多了一个Link参数的返回,里面带有了下个接口的请求地址等信息,这是符合RESTful的规范的,这种返回结构能够更好的帮助我们去梳理业务流程。
2.5 什么是状态的转移?
REST原则中的无状态通信原则:客户端负责维护应用状态,而服务端维护资源状态,服务端不应该保存客户端状态。
客户端与服务端的交互必须是无状态的,并在每一次请求中包含处理该请求所需的一切信息。
服务端不需要在请求间保留应用状态,只有在接受到实际请求的时候,服务端才会关注应用状态。
这种无状态通信原则,使得服务端和中介能够理解独立的请求和响应。
在多次请求中,同一客户端也不再需要依赖于同一服务器,方便实现高可扩展和高可用性的服务端。
但有时候我们会做出违反无状态通信原则的设计,例如利用Cookie跟踪某个服务端会话状态,常见的像J2EE里边的JSESSIONID。
这意味着,浏览器随各次请求发出去的Cookie是被用于构建会话状态的。
当然,如果Cookie保存的是一些服务器不依赖于会话状态即可验证的信息(比如认证令牌),这样的Cookie也是符合REST原则的。
“会话”状态不是作为资源状态保存在服务端的,而是被客户端作为应用状态进行跟踪的。客户端应用状态在服务端提供的超媒体的指引下发生变迁。服务端通过超媒体告诉客户端当前状态有哪些后续状态可以进入。
这些类似”下一页”之类的链接起的就是这种推进状态的作用——指引你如何从当前状态进入下一个可能的状态。
3.如何设计 RESTful API
阅读完了上述概念之后我们应该遵循如下的一些规范来进行RESTful API的设计:
- 协议
- 域名
- 版本
- 路径
- HTTP动词
- 过滤信息(Filtering)
- 状态码(Status Codes)
- 错误处理(Error handling)
- 返回结果
- Hypermedia API
其他
3.1协议
协议指的是我们请求的接口地址是采用http协议还是https协议。
3.2域名
域名指的是我们请求的接口地址所在的服务器域名,例如:api.example.com。
3.3版本
版本在我看来其实不是完全必要的,在于一些中小项目,或许更新不是那么频繁或者不需要去字面跟新,可以省去版本号。但对于一些大型项目的话,版本号还是比较有用的,当出现了bug的时候,可能我们已经更新了一堆的版本,这样有版本号的话我们很方便的可以去追溯这个问题。
通常的建议是把版本号放入到url中,例如https://api.example.com/v1/
3.4路径
路径又称”终点”(endpoint),表示API的具体网址。在RESTful架构中,每个网址代表一种资源(resource),所以网址中不能有动词,只能有名词,而且所用的名词往往与数据库的表格名对应。一般来说,数据库中的表都是同种记录的”集合”(collection),所以API中的名词也应该使用复数。
比如说:
- https://api.example.com/v1/salelists //获取销售列表
- https://api.example.com/v1/bills //获取所有账单
3.5HTTP动词
HTTP动词表示的是我们常用的请求方法:
- GET(SELECT):从服务器取出资源(一项或多项)。
- POST(CREATE):在服务器新建一个资源。
- PUT(UPDATE):在服务器更新资源(客户端提供改变后的完整资源)。
- PATCH(UPDATE):在服务器更新资源(客户端提供改变的属性)。
- DELETE(DELETE):从服务器删除资源。
例如我们上面的获取销售列表等就是GET请求。
3.6过滤信息(Filtering)
过滤信息指的其实就是条件查询,筛选符合我们条件的数据。这种通常都是前端提供额外的参数,然后后端根据参数进行筛选查询。
?limit=10:指定返回记录的数量。
- ?offset=10:指定返回记录的开始位置。
- ?page=2&per_page=100:指定第几页,以及每页的记录数。
- ?sortby=name&order=asc:指定返回结果按照哪个属性排序,以及排序顺序。
?animal_type_id=1:指定筛选条件
3.7状态码
状态码指的是返回的请求状态code,也就是我们常见的200,500等。
3.8错误处理(Error handling)
良好的接口都应该能够友好的处理错误,譬如说当发生50x错误的时候,我们在返回体中编写:
{ message:'服务器端报错,这里错误的相对应描述' }
3.9返回结果
返回结果最好是处理后转化为JSON格式,对应的就是我们获取得到的结果,通常存放在data或者object等对象里面。
3.10Hypermedia API
这个含义其实就是上述github的栗子,我们推崇在返回的数据里面携带link属性等信息,方便我们梳理接下来的业务流程。
3.11其他
其他其实包含了一些认证等信息,比如说API的身份认证应该使用OAuth 2.0框架。单个接口只完成单个任务啊等等。
本篇文章是阅读了相关资料后的一个学习笔记,希望对大家都有所帮助。