RESTful 释义
顾名思义,先看一下 RESTful 的单词拆解:
RESTful = Resources + Representation + State + Transfer + ful
我的理解是, RESTful 是指具有 资源表现层 和 状态转换 的架构设计。
资源(Resources)
资源,是指服务端向外提供的服务实体。
资源是一个抽象的概念,可以是应用程序对象、数据库记录、算法等等。每一个资源用一个 URI 来唯一标识,客户端通过这个标识对资源进行访问、操作或请求服务。
表现层(Representation)
表现层,是指资源的表现形式。
一个资源可以有多种表现形式。例如,文本数据可以用 XML 格式、JSON 格式表现,甚至可以用二进制格式表示;图片可以用 JPG 格式表现,也可以用 PNG 格式表现。
状态(State)
状态,是指资源的某种状态。
一个资源可能有多种状态。例如,资源空闲的、占用的、共享的、存在的、不存在的等。
转化(Transfer)
转化,是指对资源的操作行为。
转化的行为包括两种:
资源表现层的转化
资源状态的转化
ful
后缀是英文的一种重要构词法,通过后缀常常可以判断出一个词的词性。
ful 表形容词,意为“… 的”、“具有 … 的”。
小结
RESTful 是一种抽象的、与具体程序语言和网络协议无关的网络服务系统的架构样式。
它把在服务器端的数据和功能设计成各种的资源,并且通过 URI 定位资源、转化资源表现和状态的一种服务架构设计。
OPERATION | HTTP |
---|---|
Create | POST |
Retrieve | GET |
Update | PUT |
Delete | DELETE |
项目资源的URL应该如何设计?用名词复数还是用名词单数?一个资源需要多少个URL?用哪种HTTP方法来创建一个新的资源?可选参数应该放在哪里?那些不涉及资源操作的URL呢?实现分页和版本控制的最好方法是什么?
每个资源使用两个URL
资源集合用一个URL,具体某个资源用一个URL
用名词代替动词表示资源
推荐用复数名词
用HTTP方法操作资源
HTTP | ENDPOINT | EXPLAINATION |
---|---|---|
GET | /tickets | Retrieves a list of tickets |
GET | /tickets/12 | Retrieves a specific ticket #12 |
POST | /tickets | Creates a new ticket |
PUT | /tickets/12 | Updates ticket #12 |
PATCH | /tickets/12 | Partially |
DELETE | /tickets/12 | Deletes ticket #12 |
非资源请求用动词
有时API调用并不涉及资源(如计算,翻译或转换)。例:
GET /translate?from=zh_CN&to=en_US&text=Hello
GET /calculate?para2=23¶2=432
在这种情况下,API响应不会返回任何资源。而是执行一个操作并将结果返回给客户端。因此,您应该在URL中使用动词而不是名词,来清楚的区分资源请求和非资源请求。
过滤资源
如果资源很多,通常你不会希望服务端一次性全部的数据,API 应该提供过滤资源的能力。
这里资源过滤依靠 URL 的查询参数,通常放置在 GET 请求的URL中。
?limit=10: 限制返回的资源数量
?offset=10: 指定返回的资源的开始位置
?sortby=name&order=asc: 对资源按特定属性进行排序
在响应参数中添加浏览其它API的链接
理想情况下,不会让客户端自己构造使用REST API的URL。让我们思考一个例子。
客户端想要访问员工的薪酬表。为此,他必须知道他可以通过在员工URL(例如/employees/21/salaryStatements)中附加字符串“salaryStatements”来访问薪酬表。这个字符串连接很容易出错,且难以维护。如果你更改了访问薪水表的REST API的方式(例如变成了/employees/21/salary-statement或/employees/21/paySlips),所有客户端都将中断。
更好的方案是在响应参数中添加一个links字段,让客户端可以自动变更。
请求:
GET /employees/
响应:
//...
{
"id":1,
"name":"Paul",
"links": [
{
"rel": "salary",
"href": "/employees/1/salaryStatements"
}
]
},
//...
如果客户端完全依靠links中的字段获得薪资表,你更改了API,客户端将始终获得一个有效的URL(只要你更改了link字段,请求的URL会自动更改),不会中断。另一个好处是,你的API变得可以自我描述,需要写的文档更少。
在分页时,您还可以添加获取下一页或上一页的链接示例。只需提供适当的偏移和限制的链接示例。
GET /employees?offset=20&limit=10
{
"offset": 20,
"limit": 10,
"total": 3465,
"employees": [
//...
],
"links": [
{
"rel": "nextPage",
"href": "/employees?offset=30&limit=10"
},
{
"rel": "previousPage",
"href": "/employees?offset=10&limit=10"
}
]
}
200 OK - [GET]:服务器成功返回用户请求的数据,该操作是幂等的(Idempotent)。
201 CREATED - [POST/PUT/PATCH]:用户新建或修改数据成功。
202 Accepted - [*]:表示一个请求已经进入后台排队(异步任务)
204 NO CONTENT - [DELETE]:用户删除数据成功。
400 INVALID REQUEST - [POST/PUT/PATCH]:用户发出的请求有错误,服务器没有进行新建或修改数据的操作,该操作是幂等的。
401 Unauthorized - [*]:表示用户没有权限(令牌、用户名、密码错误)。
403 Forbidden - [*] 表示用户得到授权(与401错误相对),但是访问是被禁止的。
404 NOT FOUND - [*]:用户发出的请求针对的是不存在的记录,服务器没有进行操作,该操作是幂等的。
406 Not Acceptable - [GET]:用户请求的格式不可得(比如用户请求JSON格式,但是只有XML格式)。
410 Gone -[GET]:用户请求的资源被永久删除,且不会再得到的。
422 Unprocesable entity - [POST/PUT/PATCH] 当创建一个对象时,发生一个验证错误。
500 INTERNAL SERVER ERROR - [*]:服务器发生错误,用户将无法判断发出的请求是否成功。
在URL中强制加入版本号(???)还是在请求头中?
从始至终,都使用版本号发布您的RESTful API。将版本号放在URL中以是必需的。如果您有不兼容和破坏性的更改,版本号将让你能更容易的发布API。发布新API时,只需在增加版本号中的数字。这样的话,客户端可以自如的迁移到新API,不会因调用完全不同的新API而陷入困境。
使用直观的 “v” 前缀来表示后面的数字是版本号。
api/v1/tickets
设计流程
确定 API 提供的资源类型
确定资源间的关系
依据类型和关系来确定资源名方案
确定资源结构
为资源添加最少的方法集
通过发送POST和PUT请求均可以添加一个新的资源,但是两者的不同之处在于:
对于前者,请求者一般不能确定标识添加资源最终采用的URI,即服务端最终为成功添加的资源指定URI;
对于后者,最终标识添加资源的URI是可以由请求者控制的。也正是因为这个原因,如果发送PUT请求,我们一般直接将标识添加资源的URI作为请求的URI;对于POST请求来说,其URI一般是标识添加资源存放容器的URI。
控制器(Controller) 主要职责
输入:前端所传数据类型
处理:
1. 处理请求的参数
2. 渲染和重定向
3. 选择 Model
和 Service
4. 处理 Session
和 Cookies
输出:返回数据或跳转
前后端数据交互
1、数据的类型
变量key/value
数组
Java Bean
json字符串
前端传输数据的形式:GET,POST
表单,json字符串
统一的响应结构
- 正确信息
- 错误信息
统一的请求数据校验
统一的接口异常处理
1、规避Map、List作参数或者响应结果的方式(尤其是参数用Map来包装,这种代码有时候看起来真的让人很沮丧)
参数 | 详细解释 | 备注 |
---|---|---|
-l | use a long listing format | 以长列表方式显示(显示出文件/文件夹详细信息) |
-t | sort by modification time | 按照修改时间排序 |
-r | reverse order while sorting | 逆序排列 |
[参考]