RESTfulAPI
RESTfulAPI概念
Q:什么是RESTfulAPI?
REST一种互联网软件架构原则,如果一个架构符合REST原则,就称为RESTful架构。
REST全称Representational State Transfer,表现层状态转换,这样理解有点抽象,可以从RESTful架构的三个特征来理解。
RESTful三个特征:
- 一个URI代表一种资源。
- 客户端服务器之间传递这个资源的表现层。
- 客户端通过四个HTTP动词对服务端的资源进行操作,实现“表现层状态转换”。
Q:URI是什么?
我们上网的过程实际上是将资源互相传递的过程,这个资源可以是文本、音频、视频、图片等各种实体。一个URI(统一资源定位符)唯一标识一个资源,因此访问URI就可以访问到这个资源。
Q:表现层是什么?
我们上网时通过调用资源的URI实现与资源的交互,资源是实体,表现层是资源实体呈现出来的具体形式,例如文本是个实体,txt文件就是其表现层,当然html、xml也是它的表现层。
URI代表资源实体,因此一些网址中的.html
后缀是不必要的,因为.html
代表此资源的表现层,不属于URI的范畴,表现层应写在HTTP头信息的Accept和Content-type字段,这两个字段是用来描述表现层的。
Q:状态变化指的是什么?
上网过程中客户端与服务端的互动势必涉及到资源数据和状态的变化,而这个过程是通过HTTP协议进行的,HTTP协议是无状态协议,意味着所有的状态都保存在服务端,如果客户端想要修改资源,只能通过让服务端发生“状态变化”来完成,而这个转化是建立在表现层上的,因此就是“表现层状态变化”。
Q:四个HTTP动词指的是什么?如何对服务端资源做操作?
四个表示操作方式的动词分别是:GET、POST、PUT、DELETE,对应对资源的操作:创建、编辑、请求、删除。
简单理解就是:
- GET:请求获取URI所标识的资源。
- POST:用来新建资源(也可以用来更新资源),用URI作为标识。
- PUT:请求服务器存储一个资源,并用URI作为其标识(与POST的区别可以理解为追加修改)。
- DELETE:请求服务器删除URI所标识的资源。
Q:为什么建议使用POST替代GET?
常使用POST替代GET的原因主要包括数据传输量、安全性、隐私保护、CSRF攻击防护、数据格式多样性、以及特定操作的需求。
- 传输量:GET只能将参数作为URL的一部分传入,而URL有长度限制,POST通过HTTP消息体传递,能包含更多参数。
- 安全性:GET将参数作为URL一部分暴露在外,容易被非法获取,特别是有些参数包含敏感信息,而POST通过HTTP消息体传递参数,参数不容易被直接观察到。
- 保密性:GET会将参数在URL中暴露在外,如果参数涉及隐私同样会暴露。
- 数据格式多样性:POST请求可以使用多种数据格式(例如表单、JSON、XML等)传递数据。
RESTfulAPI接口规范
首先要明确一点,规范是为了更好地协作而指定的一套规则,团队里开发人员都遵循规范那就能提高工作效率,但是不遵循规范并不是错误的,请尊重他人的选择。
进入正题,RESTful是按照HTTP的思想进行设计的,RESTful API在请求方法、资源、地址都进行了规范,其最大限度的利用了HTTP最初的应用协议的设计理念,所以有必要知道HTTP的结构是什么样子。
http链接是很常见的,一般都具有下面的结构:
1 | schema://host[:port]/path[?query-string][#author] |
参数 | 含义 |
---|---|
shceme | 指定低层使用的协议(如http,https,ftp) |
host | 服务器的IP地址或域名 |
port | 服务器端口,可省略,默认为80 |
path | 访问资源的路径 |
query-string | 发送给http服务器的数据,常用于对资源进行筛选操作 |
anchor | 锚,链接 |
URI规范
- 不用大写;
- 用中杠
-
不用下杠_
; - URI中的名词表示资源集合时,使用复数形式。
上文中提到的path即URI,URI唯一标识资源实体,所以应该是名词,不应该有动词,动词含义应该放在HTTP协议中用四个HTTP动作(GET,POST,PUT,DELETE)来代替,如果某些动作是HTTP动词表示不了的,你就应该把动作做成一种资源,用动作的名词形式代替表示一种服务。
例如从账户A转账10000元给账户B:
1 | /* 错误URI写法 */ |
RESTfulAPI规范
设计RESTful API需要考虑以下几个方面:
资源路径
资源路径(URI):RESTful的核心是面向资源,如何规划资源路径很重要,这个资源路径与实际资源的路径没有关系,可以理解为一个服务的地址,或者接口暴露给调用方的服务访问地址。
针对不同操作(如GET,POST),服务器向用户返回的结果应该符合以下规范:- GET/collections: 返回资源对象的列表(数组)
- GET/collections/identity : 读取资源时,传入标识符(identity),服务端返回标识符指定的单个资源对象
- POST/collections : 返回新生成的资源对象
- PUT/collections/identity : 返回完整的资源对象
- PATCH/collections/identity : 返回被修改的属性
- DELETE/collections/identity : 返回一个204状态码和空响应体
HTTP动词
HTTP动词的选择其实是选择请求方式:如GET,POST,DELETE,PUT,根据服务所属的动作来选择,同时建议使用POST代替GET,特别是对安全性方面有要求或者传入参数格式比较特别。- GET : 从服务器去除资源
- POST :在服务器新建一个资源
- PUT:在服务器更新资源(客户端提供改变后的完整资源,服务端返回完整的更新字段)
- PATCH:在服务器更新资源(客户端提供改变的属性,服务端返回只发生了更新的字段)
- DELETE:从服务器删除资源
过滤信息
如果记录数量过多,服务器不可能都将它们返回给用户。这时就需要进行筛选。筛选时,API应该提供一个参数,过滤一下返回的结果。?offset = 10
:指定返回记录的开始位置?page = 2&per_page = 100
:指定第几页,以及每页的记录数?sortby = name&order = asc
:指定返回结果排序,以及排序顺序?animal_type_id = 1
:指定筛选条件返回体
服务的响应返回内容应该包装成一个返回体,同时此返回体不仅要包含服务返回的数据内容,还应包含服务的状态码和错误处理。- 状态码:当客户端发送一个请求时,服务端应当响应什么状态码,例如
404
。
常用响应状态码(在RESTful 中有重要应用): - 200 OK 服务器成功返回用户请求的数据
- 201 CREATED 新建或修改数据成功
- 204 NO CONTENT 删除数据成功
- 400 BAD REQUEST 用户发出的请求有错误
- 401 Unauthorized 表示用户没有认证,无法进行当前操作
- 403 Forbidden 表示用户的访问是被禁止的
- 422 Unprocesable Entity 当创建一个对象时,发生一个验证错误。例如创建用户资源时需要用户名、密码,而前端只提供用户名字段,那么 就要返回一个422 状态码,并返回错误信息:”密码不能为空“
- 500 INTERNAL SERVER ERROR 服务器内部错误,此时服务端无法处理任何请求。
例如:如果状态码是4xx或5xx,就应该向用户返回出错信息。一般而言,返回的信息中将error作为键名,出错信息作为键值即可1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37public enum ResponseEnum {
SUCCESS(200, "服务器成功处理了请求!"),
CREATE_SUCCESS(201, "请求成功并因此创建了一个新资源。"),
UPDATE_SUCCESS(202, "请求成功并因此更新了一个资源。"),
NO_CONTENT_SUCCESS(204, "服务器成功处理了请求,但没有返回任何内容。"),
ERROR(402, "操作失败!"),
INVALID_ARGUMENT_ERROR(400, "客户端请求有语法错误,请检查参数格式!"),
UNAUTHORIZED_ERROR(401, "权限不足,请检查访问权限!"),
NOT_FOUND_ERROR(404 ,"请求资源不存在"),
INNER_ERROR(500, "服务器内部发生错误!"),
SERVER_UNAVAILABLE_ERROR(503, "服务器当前不能处理客户端的请求!")
;
private int code;
private String message;
ResponseEnum(int code, String msg) {
this.code = code;
this.message = msg;
}
public int getCode() {
return code;
}
public String getMsg() {
return message;
}
}
- 状态码:当客户端发送一个请求时,服务端应当响应什么状态码,例如
错误处理:如当发现客户端传入的参数有问题时,该返回什么样的状态信息。
例如操作成功返回status:"success"
,操作失败返回status:"failure"
,同时报错信息也应该有,例如:error_info:index out of range
。返回结果:如果服务有返回结果要传给客户端,返回体中就要包含返回结果
一个返回体的例子:1
2
3
4
5
6
7
8
9
10
11
12
13
14{
"success": true,
"code": 200,
"message": "服务器成功处理了请求!",
"error_message": "",
"data": [
{
"name": "fjsi",
"email": "fjsi@fjsi.com",
"age": 18
}
]
}
相关链接
博主根据自己理解的RESTful API书写了一个简单项目,仅供参考:RESTful API示例
另外如果对Java的依照RESTful API规范书写Controller不清楚的,可以查看本站中SpringMVC这篇文章。