JAVA && Spring && SpringBoot2.x — 学习目录
上来一首打油诗:
动词加名词,名词用复数。
动词分五类,之间可覆盖。
名词若多级,从属或平等。
状态需明确,响应给连接。
1. 什么叫做Restful
简单来讲:Restful是一种框架的规范与约束原则,符合这种规范的架构都是RESTful架构
1.1 RESTful是什么意思?
REST是Representational State transfer (资源)表述性转移。本质上是通过表述完成资源的转移。
1.2 RESTful的结构?
RESTful的核心思想就是:客户端发出的数据操作指令都是“动词+宾语”的结构。例如GET /articles这个命令,GET是动词,/articles是宾语。
需要注意的是:根据HTTP规范,动词一律大写。
动词通常来说,其实就是五种HTTP方法,对应CRUD操作。
| 动词 | 操作 | 
|---|---|
| GET | 读取 | 
| POST | 新建 | 
| PUT | 更新 | 
| PATCH | 部分更新 | 
| DELETE | 删除 | 
作为设计基础,还是需要遵循几个原则的:
- 当标准合理的时候遵守标准。
- API应该对程序员友好,并且在浏览器地址容易输入。
- API应该简单,直观,容易使用的同时优雅。
- API应该具有足够的灵活性来支持上层ui。
- API设计权衡上述几个原则。
- GET /tickets#获取ticket列表;
- GET /tickets/12#查看某个具体的ticket;
- POST /tickets#新建一个ticket;
- PUT /tickets/12#更新ticket 12;
- DELETE /tickets/12#删除ticket 12;
显然从API用户的角度来看,“资源”应该是一个名词。即使在内存数据结构模型和资源已经有了很好的对应,API设计的时候仍然不需要把它们一对一的暴露出来,这里的关键是隐藏内部资源,暴露必须的对外资源。
2. 如何书写RESTful
2.1 动词的覆盖
有些客户端只能使用GET和POST这两种方法,服务器必须接受POST模拟其他三个方法(PUT/PATCH/DELETE)。
这时,客户端发出的HTTP请求,需要加上X-HTTP-Method-Override属性,告诉服务器应该使用哪种动词,覆盖POST方法。
POST /api/Person/4 HTTP/1.1  
X-HTTP-Method-Override: PUT
上面代码中,X-HTTP-Method-Override指定本次请求的方法是PUT,而不是POST。
2.1 宾语必须是名词
宾语就是API的URL,是Http动词作用的对象,他表述的是一个资源。应该是名词,不应该是动词。
!!!Restful反例
/getAllCars
/createNewCar
/deleteAllRedCars
2.2 宾语是单数还是复数
既然URL是名词,那么应该使用复数,还是单数?
这里没有统一的规定,但是常见的操作是读取一个集合,比如GET /articles(读取所有的文章)这里明显是复数。
为了统一起见,建议都使用复数URL,比如GET /articles/2要好于GET /article/2。
2.3 多级的URL的写法
按照Rails中标准定义的方式:
- 若定义这个资源的两个参数具有从属关系,那么生成的url就是owner/1/property/1,其中property从属于owner。比如用户1的编号为2的文章,就是users/1/articles/2。
- 如果两个资源是平等的,那么一般是作为URL中HTTP方法的参数。
举个小栗子
比如汇款动作,从账户1向账户2汇款500元。如何设计URL?
小优同学:POST /accounts/1/transfer/500/to/2;
小胖老师:答错了,请坐下。
正确的应该是:将动词转换为名称,(只是一个汇款操作)
即:POST /accounts/transaction?from=1&to=2&amount=500.00;
3. 状态码
客户端的每一次请求,服务器都必须给出回应。回应包括HTTP状态码和数据两部分。
| 状态码 | 相关操作 | 
|---|---|
| 1xx | 相关信息 | 
| 2xx | 操作成功 | 
| 3xx | 重定向 | 
| 4xx | 客户端错误 | 
| 5xx | 服务器错误 | 
这五大类共包含了100多种状态码,覆盖了绝大部分可能的情况。每一种状态码都有标准(或者是约定)解释,客户端只需要查看状态码,就可以判断出发生了什么情况,所以服务器应返回尽可能精确的1状态码。
API不需要1xx状态码,下面介绍其他四类状态码的精确含义。
3.1 2xx状态码
虽然
200状态码表示操作成功,但是不同的方法可以返回更精确的状态码。
| HTTP操作 | 状态码 | 
|---|---|
| GET | 200 ok | 
| POST | 201 created | 
| PUT | 200 ok | 
| PATCH | 200 ok | 
| DELETE | 204 no content | 
- POST返回 - 201状态码,表示生成了新的资源;
- DELETE返回 - 204状态码,表示资源已经不存在;
- 202 Accepted状态码表示服务器已经收到请求,但还未进行处理,会在未来再处理,通常用于异步操作。
HTTP/1.1 202 Accepted
{
  "task": {
    "href": "/api/company/job-management/jobs/2130040",
    "id": "2130040"
  }
}
3.2 3xx状态码
API用不到301状态码(永久重定向)和302状态码(暂时重定向,307也是这个含义),因为它们可由应用级别返回,浏览器会直接跳转,API级别可以不考虑这两种情况。
API用到的3xx状态码,主要是303 See Other,表示参考另一个URL。它与302和307含义一样,也是“暂时重定向”,区别在于302和307用于GET请求,而303用于POST、PUT和DELETE请求。收到303以后,浏览器不会自动跳转,会让用户自己决定下一步怎么办,下面是一个例子。
HTTP/1.1 303 See Other
Location: /api/orders/12345
3.3 4xx状态码
4xx状态码表示客户端错误,主要有下面几种。
| 状态码 | 含义 | 
|---|---|
| 400 Bad Request | 服务器不理解客户端请求,未做任何处理 | 
| 401 Unauthorized | 用户未提供身份验证凭证,或者没有通过身份验证 | 
| 403 Forbidden | 用户通过身份验证,但没有权限访问请求资源 | 
| 404 Not Found | 所请求资源不存在,或不可用 | 
| 405 Method Not Allowed | 用户已经通过身份验证,但是所用HTTP方法不在权限内 | 
| 410 Gone | 所请求资源已经从这个地址转移,不可再用 | 
| 415 Unsupported Media Type | 客户端要求返回格式不支持。比如API只能返回JSON,但Client要求返回XML | 
| 422 Unprocessable Entity | 客户端上传附件无法处理,导致请求失败 | 
| 429 Too Many Request | 客户端的请求次数超过限额 | 
3.4 5xx状态码
5xx状态码表示服务端错误,一般来说,API不会像用户透露服务器的详细信息,所以只要两个状态码就够了。
| 状态码 | 含义 | 
|---|---|
| 500 Internal Server Error | 客户端请求有效,服务器处理时发生了意外 | 
| 503 Service Unavailable | 客户端无法处理请求,一般用于网站维护状态 | 
4. 服务器回应
4.1 不要返回纯文本
API返回的数据格式,不应该是纯文本,而应该是一个JSON对象,因为这样才能返回标准的结构化数据。所以客户端回应的HTTP头的Content-Type属性要设为
application/json。
客户端请求时,也要明确告诉服务器,可以接受JSON格式,即请求的HTTP头的ACCEPT属性也要设为application/json。
GET /orders/2 HTTP/1.1 
Accept: application/json
4.2 发生错误时,不要返回200错误码
有一种不恰当的做法是,即使发生错误,也返回200状态码,把错误信息放在数据体里面,就像下面这种:
HTTP/1.1 200 OK
Content-Type: application/json
{
  "status": "failure",
  "data": {
    "error": "Expected at least two items in list."
  }
}
上面代码,解析数据体以后,才能得知操作失败。
这种做法实际上是取消了状态码,这是完全不可取的。正确的做法是:状态码反映发生的错误,具体的错误信息放在数据体里面返回。
HTTP/1.1 400 Bad Request
Content-Type: application/json
{
  "error": "Invalid payoad.",
  "detail": {
     "surname": "This field is required."
  }
}
4.3 提供链接
HATEOAS怎么读(Hypermedia as the engine of application state)超媒体作为应用状态引擎。【“小胖哥哥,你英语翻译太棒了”——小优】
我们知道REST是使用标准的HTTP方法来操作资源的。但仅仅因此就理解成带CURD的WEB数据库架构就太low了吧。这种说法忽略了一个核心的概念,即“超媒体即应用状态引擎(Hypermedia as the engine of application state)”。
超媒体是什么?
当你浏览Web页面的时候,从一个连接跳到一个页面,再从另一个连接跳到另外一个页面,就是利用超媒体的概念:把一个个资源链接起来。
要达到这个目的,就要求在表述表格里面加入链接来引导客户端,在《RESTFul Web Services》一书中,作者把这种具有链接的特性称为“连通性”。
RESTful 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"
}}
上面代码表示,文档中有一个link属性,用户读取这个属性就知道下一步调用什么API,rel表示这个API与当前网址的关系(collection关系,并给出该collection的网址),href表示API的路径,title表示API的标题,type表示返回类型。
Hypermedia API的设计被称为HATEOAS。GIThub的API就是这种设计,访问api.github.com就会得到一个所有可用API的网址列表。

那我们就去访问访问https://api.github.com/user这个地址吧。

参考文章:
restful 接口命名规则