什么是RESTful
出处
2000 年 Roy Fielding 的博士论文中(论文地址见下方,感兴趣的可以看看),Roy Fielding是 HTTP 规范的主要编写者之一、Apache服务器软件的作者之一、Apache基金会的第一任主席。
论文REST章节地址:Fielding Dissertation: CHAPTER 5: Representational State Transfer (REST)
论文地址:Architectural Styles and the Design of Network-based Software Architectures
解释
REST是REpresentational State Transfer的简写(全称Resource Representational State Transfer),翻译过来就是“表现层状态转移”。这句话不是正常人能理解的,我也不理解。
引用一句我能理解的话来说就是:
URL定位资源,用HTTP动词(GET,POST,PUT,DELETE)描述操作。
注:引用自https://blog.csdn.net/hjc1984117/article/details/77334616
然后拆分下Resource Representational State Transfer这四个单词:
- Resource:资源,即"数据";
- Representational:某种表现形式--"资源"具体呈现出来的形式,比如用JSON,XML,JPEG等;
- State Transfer:状态变化。通过HTTP动词实现(GET、POST、PUT、DELETE等)。互联网通信协议HTTP协议,是一个无状态协议。这意味着,所有的状态都保存在服务器端。因此,如果客户端想要操作服务器,必须通过某种手段,让服务器端发生"状态转化"(State Transfer)。而这种转化是建立在表现层之上的,所以就是"表现层状态转化"。
RESTful API就是REST风格的API,RESTful是一种软件架构风格,而不是标准。风格意思就是大家默认的但不是强制的。
RESTful 详解
用 URL
定位资源
REST 的主体是资源,所谓“资源”,即数据,就是网络上的一个具体信息,例如:一张图片,一段文字、一种服务。总之就是一个实际存在的东西,而 URL 就是用来指向这个资源的。
https://api.example.com/users
这个 URL 一看就知道是对 user 资源的操作。URL 中只使用名词来指定资源,不包含操作。为什么呢?
如果要包含操作,那至少有增删改查四种,那么上例中的一个接口至少要变成四个:
https://api.example.com/add_user
https://api.example.com/delete_user
https://api.example.com/update_use
https://api.example.com/get_user
如果可能还会有更多。
用 HTTP 动词描述操作
那怎么描述操作呢?答案就是用 HTTP 动词。
HTTP 动词,可能很多人第一眼看到的时候有点蒙,不知道是啥,其实就是我们请求网页时用的 GET、POST 等操作。我们平时用的最多的就是 GET 和 POST(例如写爬虫的时候,基本都是这两种),常用的还有 PUT、PATCH、DELETE 。
对资源的操作,无外乎 CRUD(增删改查),RESTful 中,每个 HTTP 动词对应一个 CRUD 操作。
- GET:对应 Retrieve 操作(查询操作)
- POST:对应 Create 操作
- DELETE:对应 Delete 操作
- PUT:对应 Update 操作
- PATCH:对应 Update 操作
POST 和 PUT 的区别
一般说到 HTTP 动词对应 CRUD 的时候,PUT 都是对应 Update 操作的。但其实,PUT 也可以做 Create 操作。二者的区别在于:
- URL:POST 不需要指定到个体,例如新增 user 的接口
POST /api/users
。 PUT 的 URL 需要指定到具体的个体,例如PUT /api/users/1
,如果 1 这个 user 存在,则 Update,否则 Create。这个很好理解,POST 确定是新增,insert 的时候是不需要 where 条件的;PUT 则不行,update 的时候不加 where。另外,PUT 的时候,也不是每个 user 就要建一个接口的,这里需要用到的就是路由,一般是写成PUT /api/users/{id}
,这样就具有一般性了。路由在这里就不展开讲了。 - 幂等性:PUT 是幂等的,而 POST 是非幂等的。关于幂等性,见下文。
PATCH 和 PUT 的区别
PATCH 是 2010 后成为的正式 http 方法,它是对 PUT 的补充。在没有 PATCH 之前,都是用 PUT 进行更新操作,这时候我们的接口中通常会有一个逻辑规则,如:如果对象的一个属性值为null
,那么就不更新该属性(字段)值,通过这种方式来避免全部覆盖的操作。现在有了 PATCH 就解决了这种判断,在 PUT 操作中不管属性是不是 null
,都进行更新,在 PATCH 接口中就对非 null
的进行更新。另外,PATCH 是非幂等的。
变通的 POST
按照 REST 建议,查询操作要使用 GET 方法,但是实际情况中处理起来比较麻烦,如:报表统计查询,需要传递的参数很多,如果采用 GET 方法,那么接口接收的参数非常多,接口很难看,通常会封装为 java 对象,但 GET 方法又不支持对象传参,所以很蛋疼。
对于这种情况,最简单的方式就是改成 POST 方式,而且很多公司都是这么干的。可见 REST 只是建议,并非强制约束。
幂等性
幂等(Idempotence)本来是一个数学上的概念,后来拓展到计算机领域,描述为:
一个操作、方法或者服务,其任意多次执行所产生的影响均与一次执行的影响相同。
一个幂等的方法,使用同样的参数,对它进行多次调用和一次调用,对系统产生的影响是一样的。所以,对于幂等的方法,不用担心重复执行会对系统造成任何改变。
举个例子,用户 X 的手机话费余额为 2 元,他用支付宝给手机充了 100 元话费,如果将这个操作描述为“给 X 的账户余额增加 100 元”那就是非幂等的,重复操作几次运营商就亏大了。但是,如果将这个操作描述为“将 X 的账户余额设置为 102 元”,那这个操作就是幂等的。简单来说:
- 幂等操作:将账户 X 的余额设置为 102 元;
- 非幂等操作:将账户 X 的余额增加 100 元。
注意:这里的幂等性的例子并不严谨,本文主要不是讲幂等性的,所以只是举个简单的例子,不做深入探讨。
RESTful 的其他细节
命名规则
- 全部小写,用 _ 或 - 线连接。(之所以不用驼峰命名法,是因为早期的 URI 一般都是表示服务器上的文件路径,而不同服务器对大小写的敏感性是不同的,为了兼容不同服务器所以才规定不能混用大小写字母。)
- URL 中只用名词指定资源,因为 REST 的核心是资源,而表示资源的词语天然就是名词。
- 资源用复数表示。
版本
一种方法是在 URL 中添加版本号,例如:
https://api.example.com/v1/users
另一种方法是将版本号加在 HTTP 请求头信息的 Accept 字段中,例如:
Accept: version=1.0
网上能找到的版本号加在 URL 中的例子,都是如我上例所示的写法。但是 Jack_Zeng 指出,这样写容易有歧义,会让人误以为 v1 也是资源的一部分,一般都是这么写:
https://api.example.com/users?api-version=1
常用 HTTP 状态码
http 状态码有 100 多种,我们并不需要全部用到,只需要了解其中常用的就可以了。
- 200 – OK – 一切正常
- 201 – OK – 新资源已经被创建
- 204 – OK – 资源删除成功
- 304 – 没有变化,客户端可以使用缓存数据
- 400 – Bad Request – 调用不合法,确切的错误应该在 error payload 中描述
- 401 – 未认证,调用需要用户通过认证
- 403 – 不允许的,服务端正常解析和请求,但是调用被回绝或者不被允许
- 404 – 未找到,指定的资源不存在
- 422 – 不可指定的请求体:只有服务器不能处理实体时使用,比如图像不能被格式化,或者重要字段丢失
- 500 – Internal Server Error:标准服务端错误,开发人员应该尽量避开这种错误
使用标准的http状态码可以让人看到 http status code
就知道结果如何。
当然这也只是RESTful风格的一种体现,而不是标准。