REST(Representational State Transfer)中文含义是表述性状态转移,它指的是一组架构约束条件和原则(它是一种设计风格而不是标准),如果一个架构符合REST的约束条件和原则,我们就称它为RESTful架构。理论上REST架构风格并不是绑定在HTTP上,只不过目前HTTP是唯一与REST相关的实例,但不要形成固定思维。目前在三种主流的Web服务实现方案中,因为REST模式的Web服务与复杂的SOAP和XML-RPC对比来讲明显的更加简洁,越来越多的web服务开始采用REST风格设计和实现。REST的设计标准有下面的一些:
- 网络上的所有事物都被抽象为资源(resource),在REST的世界中,资源即状态,而互联网就是一个巨大的状态机,每个网页是其一个状态;URI是状态的表述;REST风格的应用则是从一个状态迁移到下一个状态的状态转移过程。早期互联网只有静态页面的时候,通过超链接在静态网页间浏览跳转的page->link->page->link…模式就是一种典型的状态转移过程。也就是说早期的互联网就是天然的REST;
- 每个资源对应一个唯一的资源标识符(resource identifier),系统中的每一个对象或是资源都可以通过一个唯一的 URI 来进行寻址,URI 的结构应该简单、可预测且易于理解,比如定义目录结构式的URI;
- 通过通用的连接器接口(generic connector interface)对资源进行操作,建立创建、检索、更新和删除(CRUD:Create, Retrieve, Update and Delete)操作与HTTP方法之间的一对一映射,主要如下:
- 若要在服务器上创建资源,应该使用POST方法;
- 若要检索某个资源,应该使用GET方法;
- 若要更新或者添加资源,应该使用PUT方法;
- 若要删除某个资源,应该使用DELETE方法。
- 对资源的各种操作不会改变资源标识符;
- 所有的操作都是无状态的(stateless),对服务器端的请求应该是无状态的,完整、独立的请求不要求服务器在处理请求时检索任何类型的应用程序上下文或状态,无状态约束使服务器的变化对客户端是不可见的,因为在两次连续的请求中,客户端并不依赖于同一台服务器。一个客户端从某台服务器上收到一份包含链接的文档,当它要做一些处理时,这台服务器宕掉了,可能是硬盘坏掉而被拿去修理,可能是软件需要升级重启——如果这个客户端访问了从这台服务器接收的链接,它不会察觉到后台的服务器已经改变了。通过超链接实现有状态交互,即请求消息是自包含的(每次交互都包含完整的信息),有多种技术实现了不同请求间状态信息的传输,例如 URI 重新,cookies 和隐藏表单字段等,状态可以嵌入到应答消息里,这样一来状态在接下来的交互中仍然有效。REST 风格应用可以实现交互,但它却天然地具有服务器无状态的特征。在状态迁移的过程中,服务器不需要记录任何 Session,所有的状态都通过 URI 的形式记录在了客户端。更准确地说,这里的无状态服务器,是指服务器不保存会话状态(Session);而资源本身则是天然的状态,通常是需要被保存的;这里所指无状态服务器均指无会话状态服务器。
【总结】
什么是RESTful架构—
(1)每一个URI代表一种资源;
(2)客户端和服务器之间,传递这种资源的某种表现层;
(3)客户端通过四个HTTP动词,对服务器端资源进行操作,实现"表现层状态转化"。
1. 基础
- API与用户的通信协议总是用
https
协议; - API尽量部署到专用域名下,如
https://api.example.com
; - 将API的版本号放入URL中,如
https://api.example.com/v1/
,此外,还可以将其放在HTTP头信息中,但不如放入URL方便和直观; - 路径又称"终点"(endpoint),表示API的具体网址,在RESTful架构中,每个网址代表一种资源(resource),所以网址中不能有动词(具体动词表现在像
get
、post
这些方法上),只能有名词,而且所用的名词往往与数据库的表格名对应。一般来说,数据库中的表都是同种记录的"集合"(collection),所以API中的名词也应该使用复数,如一个提供动物园信息的API可以像下面的这样:https://api.example.com/v1/zoos
、https://api.example.com/v1/animals
等; - 对资源进行具体操作时,主要表现在方法层面,比如:
GET /zoos
:列出所有动物园;POST /zoos
:新建一个动物园;GET /zoos/ID
:获取某个指定动物园的信息;PUT /zoos/ID
:更新某个指定动物园的信息(提供该动物园的全部信息);PATCH /zoos/ID
:更新某个指定动物园的信息(提供该动物园的部分信息);DELETE /zoos/ID
:删除某个动物园;GET /zoos/ID/animals
:列出某个指定动物园的所有动物;DELETE /zoos/ID/animals/ID
:删除某个指定动物园的指定动物;- 【注意】
PUT
和PATCH
都是更新资源,但前者需要客户端提供改变后的完整资源,而后者只需要客户端提供改变的属性即可;
- 过滤信息,API提供参数可以过滤返回结果,常见的参数有:
?limit=10
:指定返回记录的数量,这里是10;?offset=10
:指定返回记录的开始位置;?page=2&per_page=100
:指定第几页,以及每页的记录数;?sortby=name&order=asc
:指定返回结果按照哪个属性排序,以及排序顺序;?animal_type_id=1
:指定筛选条件;- 【注意】参数的设计允许存在冗余,即允许API路径和URL参数偶尔有重复;
- 错误的信息的处理:如果状态码是
4xx
,就应该向用户返回出错信息。一般来说,返回的信息中将error
作为键名,出错信息作为键值即可,如error: "Invalid API key"
; - 不同接口调用返回的结果应该符合如下的规范:
GET /collection
:返回资源对象的列表(数组);GET /collection/resource
:返回单个资源对象;POST /collection
:返回新生成的资源对象;PUT /collection/resource
:返回完整的资源对象;PATCH /collection/resource
:返回完整的资源对象;DELETE /collection/resource
:返回一个空文档;
- API的身份认证应该使用
OAuth 2.0
框架; - 服务器返回的数据格式,应该尽量使用JSON,避免使用XML;
- Hypermedia API,即超媒体API,Hypermedia API的设计被称为HATEOAS。返回结果中提供链接,连向其他API方法,使得用户不查文档,也知道下一步应该做什么,如:向
api.example.com
请求得到:
{
"link": {
"rel": "collection https://www.example.com/zoos",
"href": "https://api.example.com/zoos",
"title": "List of zoos",
"type": "application/vnd.yourformat+json"
}
}
rel
表示这个API
与当前网址的关系(collection关系,并给出该collection的网址),href
表示API的路径,title
表示API的标题,type
表示返回类型;
REST API案例(用户和订单):
注:很多时候,PUT
和POST
存在混淆,之前片面的将PUT
理解为资源的替换(我单纯的强调替换),POST
是创建,但前段时间在阅读ES文档时发现,他每次创建索引使用的都是PUT
方法,很好奇为什么不用POST
,仔细一想,也是PUT
的幂等性在某一方面也保证了资源的唯一性,ES的索引也确实只允许1个,而POST
则会重复创建,这样一想也就通了,上述只是一个场景,具体使用POST
还是PUT
也是受业务场景的影响,并不是说创建资源一定使用POST
,更新资源一定用PUT
。
【总结】
REST是面向资源的(非常重要),而资源是通过URI进行暴露,URI的设计只要负责把资源通过合理方式暴露出来就可以了,对资源的操作与它无关,操作是通过HTTP动词来体现,所以REST通过URI暴露资源时,会强调不要在URI中出现动词。