前言
最近发现小伙伴们写的API不仅仅有Get/Post,还有大量的Put/Patch/Delete,其实是有点疑惑的:所有的这些操作使用Post不就都能搞定吗?事实确实如此,Post能够搞定一切的需求。那为什么还要使用专门的Put、Patch、Delete呢?理由就是为了构建Restful架构。
HTTP/1.1的八种方法
HTTP(HyperText Transfer Protocol,超文本传输协议)是应用层的无状态网络协议,2015年提出了HTTP2.0,但是目前用得最多的还是HTTP1.1。HTTP1.1定义了八种方法来操作资源:
方法 | 初始来源 | 作用描述 |
---|---|---|
Get | HTTP 1.0 | 请求指定的页面信息,并返回实体主体。 |
Post | HTTP 1.0 | 向指定资源提交数据进行处理请求(例如提交表单或者上传文件)。 数据被包含在请求体中。 POST请求可能会导致新的资源的建立和/或已有资源的修改。 |
Head | HTTP 1.0 | 类似于get请求,只不过返回的响应中没有具体的内容,用于获取报头 |
Put | HTTP 1.1 | 从客户端向服务器传送的数据取代指定的文档的内容。 |
Delete | HTTP 1.1 | 请求服务器删除指定的页面。 |
Connect | HTTP 1.1 | HTTP/1.1协议中预留给能够将连接改为管道方式的代理服务器。 |
Options | HTTP 1.1 | 这个方法可使服务器传回该资源所支持的所有HTTP请求方法。 允许客户端查看服务器的性能。 |
Trace | HTTP 1.1 | 回显服务器收到的请求,主要用于测试或诊断。 |
Rest和Restful API
(崩溃,都快写完了死机一下,又得从这里开始重写……)
Rest(Representational State Transfer,表述状态转移)在2000年Roy Fielding的博士论文《Architectural Styles and the Design of Network-based Software Architectures》中首次被提出,指的是一组架构约束条件和原则。符合这些约束条件和原则框架的API就是Restful API。
简单地总结这些约束条件和原则就是,URL定位资源,HTTP动词描述操作。
1、资源和表述
通常Web资源可以使用URI(Uniform Resource Identifier,统一资源标识符)来定位,URL是URI的一个子集,URL除了确定资源,还确定了访问方式(是用HTTP呢,FTP呢,还是LDAP呢),例如官方的例子,这些都是URI,但只有部分是URL:
ftp://ftp.is.co.za/rfc/rfc1808.txt (also a URL because of the protocol)
http://www.ietf.org/rfc/rfc2396.txt (also a URL because of the protocol)
ldap://[2001:db8::7]/c=GB?objectClass?one (also a URL because of the protocol)
mailto:[email protected] (also a URL because of the protocol)
news:comp.infosystems.www.servers.unix (also a URL because of the protocol)
tel:+1-816-555-1212
telnet://192.0.2.16:80/ (also a URL because of the protocol)
Rest对资源的表述具体的约束:
(1)资源的格式
【只能使用名词,不能使用动词】
举个例子,通常的URL会这样设计:
http://www.bewindoweb.com/getArticle?id=1
而Restful API是这样的:
http://www.bewindoweb.com/articles/1
看起来更像是某个资源的位置了,而不管具体的访问方法。
【问号用来过滤】
还是那个例子,我们想要对文章内容分页获取,普通的设计:
http://www.bewindoweb.com/getArticle?id=1&pageNo=1
而Restful API是这样的:
http://www.bewindoweb.com/articles/1?pageNo=1
id并不使用问号,是因为它是资源定位的一部分;pageNo使用问号,是因为在对这个资源进行过滤操作,过滤可以包括pageNo、limit、state=0等等。
【单数和复数】
没有统一规定,但明显复数比单数好,例如articles/1
比article/1
更好,因为文章可能有很多篇。
【版本号】
可以在URL里面加入版本号,如:
http://www.bewindoweb.com/v1/article/1
(2)统一的访问接口
Rest规定使用HTTP统一的Get、Post、Put、Patch、Delete来对资源进行访问。这里多了一个Patch,Patch是2010年RFC5789新增的HTTP请求方式,然而目前大多数容器都不支持,部分浏览器也不支持,HTML4只支持Get/Post,HTML5也增加了Put/Delete而已。所以对于Patch,在处理的时候需要去查询具体的解决方法。在讲述这些接口的作用前,了解两个概念:
【安全性(Safety)】
无论请求多少次,都不会改变服务器的状态。
例如,无论使用Get请求多少次文章,都不会改变文章具体的数据。
【幂等性(Idempotent)】
无论对资源操作多少次,结果总是一样的。
例如,采用PUT提交修改后的文章,无论操作多少次,修改后的文章内容都是一样的;而用POST让银行卡余额减少200,每次POST之后银行卡的余额都会发生变化。
所以,总结一下这5个请求方法:
请求方法 | 安全性 | 幂等性 | 作用 |
---|---|---|---|
Get | 安全 | 幂等 | 获取表示 变更时获取表示(缓存) |
Post | 不安全 | 不幂等 | 服务端的实例号创建资源 创建子资源 |
Put | 不安全 | 幂等 | 客户端的实例号创建资源 替换的方式更新资源 |
Patch | 不安全 | 幂等 | 部分更新资源 |
Delete | 不安全 | 幂等 | 删除资源 |
根据服务端实例号创建资源:POST /items,服务端生成uuid。如果发生问题,服务端会重新生成uuid。
根据客户端实例号创建资源:PUT /items/31a1576d-7149-461a-a631-38bc11a5b2d3,利用幂等特性,无论出现什么问题,uuid不会变。
部分更新资源:Patch user/1 + 参数username=bwb,只需要携带一个参数即可,不需要全部的user属性。
(3)多种表现形式
客户端根据Accept、服务端根据Content-Type来进行协商,可以使用XML、Json等等很多表现形式。
2、资源的链接
资源之间需要链接起来,那么就要求表述格式里面加入链接来引导客户端,例如:
【请求】
GET https://api.bewindoweb.com/articles/1 HTTP/1.1
Accept: application/json
【响应】
HTTP/1.1 Status: 200 OK
Link: <https://api.bewindowb.com/articles/1?page=2>; rel="next",
<https://api.bewindoweb.com/articles/1?page=3>; rel="last"
Content-Type:application/json; charset=utf-8
[
{
.....
}
]
响应头里面包含了如何访问下一页和尾页的链接。
3、状态和转移
Rest是无状态通信的,每一次请求都看作是全新的请求,是不会存在JSESSIONID这样的Cookie的。服务端只维护资源状态,并不关心客户端的状态(不会保存session);客户端才维护应用状态,所以状态转移指的是客户端的状态转移。
举个例子,如果你想要查询工资,那么你需要经过登录→工资界面→工资数据,这是普通的Session的有状态通信;如果你输入一个URL立刻得到了工资数据,这就是符合Rest要求的架构。
很明显可以看出一个问题是,资源的安全性应该如何保障?目前通用的做法是JWT(JSON Web Token)进行认证和授权。
4、状态码
Rest要求返回具体的状态码,而不是出错返回200,然后再在Json里面描述出错信息。简单列举一些状态码:
状态码 | 描述 |
---|---|
200 | 操作完成(更新成功、删除成功) |
201 | 新资源被创建 |
204 | 资源为空 |
304 | 没有变化,客户端可以使用缓存 |
400 | 非法调用(参数错误) |
401 | 未认证 |
403 | 不允许访问 |
404 | 资源不存在 |
500 | 通用错误 |
503 | 服务器当前无法处理请求 |
总结
Restful API非常适合于分布式服务器提供接口服务,认证逻辑简单,资源控制清晰,可以跨域等等,不需要保存任何会话数据,值得实践。