{
“status”: “success”,
“data”: {}
}
“`
盡管HTTP狀態(tài)碼返回`200 OK`,但我不能完全確定它有沒有處理我的請求失敗。
實(shí)際上,[API](http://www.dlbhg.com/wiki/api/)可以返回如下響應(yīng):
“`
HTTP/1.1 400 Bad Request
Content-Type: application/json{
“error”: “Expected at least three items in the list.”
}
“`
## HTTP狀態(tài)碼
所有的 `API` 響應(yīng),`必須` 遵守 `HTTP` 設(shè)計(jì)規(guī)范,`必須` 選擇合適的 `HTTP` 狀態(tài)碼。`一定不可` 所有接口都返回狀態(tài)碼為 `200` 的 `HTTP` 響應(yīng),如:
“`
HTTP/1.1 200 ok
Content-Type: application/json
Server: example.com
{
“code”: 0,
“msg”: “success”,
“data”: {
“username”: “username”
}
}
“`
或
“`
HTTP/1.1 200 ok
Content-Type: application/json
Server: example.com
{
“code”: -1,
“msg”: “該活動(dòng)不存在”,
}
“`
下表列舉了常見的 `HTTP` 狀態(tài)碼
| 狀態(tài)碼 | 描述 |
| — | — |
| 1xx | 代表請求已被接受,需要繼續(xù)處理 |
| 2xx | 請求已成功,請求所希望的響應(yīng)頭或數(shù)據(jù)體將隨此響應(yīng)返回 |
| 3xx | 重定向 |
| 4xx | 客戶端原因引起的錯(cuò)誤 |
| 5xx | 服務(wù)端原因引起的錯(cuò)誤 |
> 只有來自客戶端的請求被正確的處理后才能返回 `2xx` 的響應(yīng),所以當(dāng) API 返回 `2xx` 類型的狀態(tài)碼時(shí),前端 `必須` 認(rèn)定該請求已處理成功。
必須強(qiáng)調(diào)的是,所有 `API“一定不可` 返回 `1xx` 類型的狀態(tài)碼。當(dāng) `API` 發(fā)生錯(cuò)誤時(shí),`必須` 返回出錯(cuò)時(shí)的詳細(xì)信息。目前常見返回錯(cuò)誤信息的方法有兩種:
1、將錯(cuò)誤詳細(xì)放入 `HTTP` 響應(yīng)首部;
“`
X-MYNAME-ERROR-CODE: 4001
X-MYNAME-ERROR-MESSAGE: Bad authentication token
X-MYNAME-ERROR-INFO: http://docs.example.com/api/v1/authentication
“`
2、直接放入響應(yīng)實(shí)體中;
“`
HTTP/1.1 401 Unauthorized
Server: nginx/1.11.9
Content-Type: application/json
Transfer-Encoding: chunked
Cache-Control: no-cache, private
Date: Sun, 24 Jun 2018 10:02:59 GMT
Connection: keep-alive
{“error_code”:40100,”message”:”Unauthorized”}
“`
考慮到易讀性和客戶端的易處理性,我們 `必須` 把錯(cuò)誤信息直接放到響應(yīng)實(shí)體中,并且錯(cuò)誤格式 `應(yīng)該` 滿足如下格式:
“`
{
“message”: “您查找的資源不存在”,
“error_code”: 404001
}
“`
其中錯(cuò)誤碼(`error_code`)`必須` 和 `HTTP` 狀態(tài)碼對應(yīng),也方便錯(cuò)誤碼歸類,如:
“`
HTTP/1.1 429 Too Many Requests
Server: nginx/1.11.9
Content-Type: application/json
Transfer-Encoding: chunked
Cache-Control: no-cache, private
Date: Sun, 24 Jun 2018 10:15:52 GMT
Connection: keep-alive
{“error_code”:429001,”message”:”你操作太頻繁了”}
“`
“`
HTTP/1.1 403 Forbidden
Server: nginx/1.11.9
Content-Type: application/json
Transfer-Encoding: chunked
Cache-Control: no-cache, private
Date: Sun, 24 Jun 2018 10:19:27 GMT
Connection: keep-alive
{“error_code”:403002,”message”:”用戶已禁用”}
“`
`應(yīng)該` 在返回的錯(cuò)誤信息中,同時(shí)包含面向開發(fā)者和面向用戶的提示信息,前者可方便開發(fā)人員調(diào)試,后者可直接展示給終端用戶查看如:
“`
{
“message”: “直接展示給終端用戶的錯(cuò)誤信息”,
“error_code”: “業(yè)務(wù)錯(cuò)誤碼”,
“error”: “供開發(fā)者查看的錯(cuò)誤信息”,
“debug”: [
“錯(cuò)誤堆棧,必須開啟 debug 才存在”
]
}
“`
下面詳細(xì)列舉了各種情況 API 的返回說明。
### 200 ok
`200` 狀態(tài)碼是最常見的 `HTTP` 狀態(tài)碼,在所有 __成功__ 的 `GET` 請求中,`必須` 返回此狀態(tài)碼。`HTTP` 響應(yīng)實(shí)體部分 `必須` 直接就是數(shù)據(jù),不要做多余的包裝。
錯(cuò)誤示例:
“`
HTTP/1.1 200 ok
Content-Type: application/json
Server: example.com
{
“user”: {
“id”:1,
“nickname”:”fwest”,
“username”: “example”
}
}
“`
正確示例:
1、獲取單個(gè)資源詳情
“`
{
“id”: 1,
“username”: “godruoyi”,
“age”: 88,
}
“`
2、獲取資源集合
“`
[
{
“id”: 1,
“username”: “godruoyi”,
“age”: 88,
},
{
“id”: 2,
“username”: “foo”,
“age”: 88,
}
]
“`
3、額外的媒體信息
“`
{
“data”: [
{
“id”: 1,
“avatar”: “https://lorempixel.com/640/480/?32556”,
“nickname”: “fwest”,
“last_logined_time”: “2018-05-29 04:56:43”,
“has_registed”: true
},
{
“id”: 2,
“avatar”: “https://lorempixel.com/640/480/?86144”,
“nickname”: “zschowalter”,
“last_logined_time”: “2018-06-16 15:18:34”,
“has_registed”: true
}
],
“meta”: {
“pagination”: {
“total”: 101,
“count”: 2,
“per_page”: 2,
“current_page”: 1,
“total_pages”: 51,
“links”: {
“next”: “http://api.example.com?page=2”
}
}
}
}
“`
> 其中,分頁和其他額外的媒體信息,必須放到 `meta` 字段中。
### 201 Created
當(dāng)服務(wù)器創(chuàng)建數(shù)據(jù)成功時(shí),`應(yīng)該` 返回此狀態(tài)碼。常見的應(yīng)用場景是使用 `POST` 提交用戶信息,如:
– 添加了新用戶
– 上傳了圖片
– 創(chuàng)建了新活動(dòng)
等,都可以返回 `201` 狀態(tài)碼。需要注意的是,你可以選擇在用戶創(chuàng)建成功后返回新用戶的數(shù)據(jù)
“`
HTTP/1.1 201 Created
Server: nginx/1.11.9
Content-Type: application/json
Transfer-Encoding: chunked
Date: Sun, 24 Jun 2018 09:13:40 GMT
Connection: keep-alive
{
“id”: 1,
“avatar”: “https://lorempixel.com/640/480/?32556”,
“nickname”: “fwest”,
“last_logined_time”: “2018-05-29 04:56:43”,
“created_at”: “2018-06-16 17:55:55”,
“updated_at”: “2018-06-16 17:55:55”
}
“`
也可以返回一個(gè)響應(yīng)實(shí)體為空的 `HTTP Response` 如:
“`
HTTP/1.1 201 Created
Server: nginx/1.11.9
Content-Type: text/html; charset=UTF-8
Transfer-Encoding: chunked
Date: Sun, 24 Jun 2018 09:12:20 GMT
Connection: keep-alive
“`
> 這里我們 `應(yīng)該` 采用第二種方式,因?yàn)榇蠖鄶?shù)情況下,客戶端只需要知道該請求操作成功與否,并不需要返回新資源的信息。
### 202 Accepted
該狀態(tài)碼表示服務(wù)器已經(jīng)接受到了來自客戶端的請求,但還未開始處理。常用短信發(fā)送、郵件通知、模板消息推送等這類很耗時(shí)需要隊(duì)列支持的場景中;
> 返回該狀態(tài)碼時(shí),響應(yīng)實(shí)體 `必須` 為空。
“`
HTTP/1.1 202 Accepted
Server: nginx/1.11.9
Content-Type: text/html; charset=UTF-8
Transfer-Encoding: chunked
Date: Sun, 24 Jun 2018 09:25:15 GMT
Connection: keep-alive
“`
### 204 No Content
該狀態(tài)碼表示響應(yīng)實(shí)體不包含任何數(shù)據(jù),其中:
– 在使用 `DELETE` 方法刪除資源 __成功__ 時(shí),`必須` 返回該狀態(tài)碼
– 使用 `PUT`、`PATCH` 方法更新數(shù)據(jù) __成功__ 時(shí),也 `應(yīng)該` 返回此狀態(tài)碼
“`
HTTP/1.1 204 No Content
Server: nginx/1.11.9
Date: Sun, 24 Jun 2018 09:29:12 GMT
Connection: keep-alive
“`
### 3xx 重定向
所有 `API“不該` 返回 `3xx` 類型的狀態(tài)碼。因?yàn)?`3xx` 類型的響應(yīng)格式一般為下列格式:
“`
HTTP/1.1 302 Found
Server: nginx/1.11.9
Content-Type: text/html; charset=UTF-8
Transfer-Encoding: chunked
Cache-Control: no-cache, private
Date: Sun, 24 Jun 2018 09:41:50 GMT
Location: https://example.com
“`
所有 `API“一定不可` 返回純 `HTML` 結(jié)構(gòu)的響應(yīng);若一定要使用重定向功能,`可以` 返回一個(gè)響應(yīng)實(shí)體為空的 `3xx` 響應(yīng),并在響應(yīng)頭中加上 `Location` 字段:
“`
HTTP/1.1 302 Found
Server: nginx/1.11.9
Content-Type: text/html; charset=UTF-8
Transfer-Encoding: chunked
Date: Sun, 24 Jun 2018 09:52:50 GMT
Location: https://godruoyi.com
Connection: keep-alive
“`
### 400 Bad Request
由于明顯的客戶端錯(cuò)誤(例如,請求語法格式錯(cuò)誤、無效的請求、無效的簽名等),服務(wù)器 `應(yīng)該` 放棄該請求。
> 當(dāng)服務(wù)器無法從其他 4xx 類型的狀態(tài)碼中找出合適的來表示錯(cuò)誤類型時(shí),都 `必須` 返回該狀態(tài)碼。
“`
HTTP/1.1 400 Bad Request
Server: nginx/1.11.9
Content-Type: application/json
Transfer-Encoding: chunked
Cache-Control: no-cache, private
Date: Sun, 24 Jun 2018 13:22:36 GMT
Connection: keep-alive
{“error_code”:40000,”message”:”無效的簽名”}
“`
### 401 Unauthorized
該狀態(tài)碼表示當(dāng)前請求需要身份認(rèn)證,以下情況都 `必須` 返回該狀態(tài)碼。
– 未認(rèn)證用戶訪問需要認(rèn)證的 API
– access_token 無效/過期
> 客戶端在收到 `401` 響應(yīng)后,都 `應(yīng)該` 提示用戶進(jìn)行下一步的登錄操作。
“`
HTTP/1.1 401 Unauthorized
Server: nginx/1.11.9
Content-Type: application/json
Transfer-Encoding: chunked
WWW-Authenticate: JWTAuth
Cache-Control: no-cache, private
Date: Sun, 24 Jun 2018 13:17:02 GMT
Connection: keep-alive
“message”:”Token Signature could not be verified.”,”error_code”: “40100”}
“`
### 403 Forbidden
該狀態(tài)碼可以簡單的理解為沒有權(quán)限訪問該請求,服務(wù)器收到請求但拒絕提供服務(wù)。
如當(dāng)普通用戶請求操作管理員用戶時(shí),`必須` 返回該狀態(tài)碼。
“`
HTTP/1.1 403 Forbidden
Server: nginx/1.11.9
Content-Type: application/json
Transfer-Encoding: chunked
Cache-Control: no-cache, private
Date: Sun, 24 Jun 2018 13:05:34 GMT
Connection: keep-alive
{“error_code”:40301,”message”:”權(quán)限不足”}
“`
### 404 Not Found
該狀態(tài)碼表示用戶請求的資源不存在,如
– 獲取不存在的用戶信息 (get /users/9999999)
– 訪問不存在的端點(diǎn)
都 `必須` 返回該狀態(tài)碼,若該資源已永久不存在,則 `應(yīng)該` 返回 `401` 響應(yīng)。
### 405 Method Not Allowd
當(dāng)客戶端使用的 `HTTP` 請求方法不被服務(wù)器允許時(shí),`必須` 返回該狀態(tài)碼。
> 如客戶端調(diào)用了 `POST` 方法來訪問只支持 GET 方法的 API
該響應(yīng) `必須` 返回一個(gè) `Allow` 頭信息用以表示出當(dāng)前資源能夠接受的請求方法的列表。
“`
HTTP/1.1 405 Method Not Allowed
Server: nginx/1.11.9
Content-Type: application/json
Transfer-Encoding: chunked
Allow: GET, HEAD
Cache-Control: no-cache, private
Date: Sun, 24 Jun 2018 12:30:57 GMT
Connection: keep-alive
{“message”:”405 Method Not Allowed”,”error_code”: 40500}
“`
### 406 Not Acceptable
`API` 在不支持客戶端指定的數(shù)據(jù)格式時(shí),應(yīng)該返回此狀態(tài)碼。如支持 `JSON` 和 `XML` 輸出的 `API` 被指定返回 `YAML` 格式的數(shù)據(jù)時(shí)。
> Http 協(xié)議一般通過請求首部的 Accept 來指定數(shù)據(jù)格式
### 408 Request Timeout
客戶端請求超時(shí)時(shí) `必須` 返回該狀態(tài)碼,需要注意的時(shí),該狀態(tài)碼表示 __客戶端請求超時(shí)__,在涉及第三方 `API`調(diào)用超時(shí)時(shí),`一定不可` 返回該狀態(tài)碼。
### 409 Gonfilct
該狀態(tài)碼表示因?yàn)檎埱蟠嬖跊_突無法處理。如通過手機(jī)號(hào)碼提供注冊功能的 `API`,當(dāng)用戶提交的手機(jī)號(hào)已存在時(shí),`必須` 返回此狀態(tài)碼。
“`
HTTP/1.1 409 Conflict
Server: nginx/1.11.9
Content-Type: application/json
Transfer-Encoding: chunked
Cache-Control: no-cache, private
Date: Sun, 24 Jun 2018 12:19:04 GMT
Connection: keep-alive
{“error_code”:40900,”message”:”手機(jī)號(hào)已存在”}
“`
### 410 Gone
和 `404` 類似,該狀態(tài)碼也表示請求的資源不存在,只是 `410` 狀態(tài)碼進(jìn)一步表示所請求的資源已不存在,并且未來也不會(huì)存在。在收到 `410` 狀態(tài)碼后,客戶端 `應(yīng)該` 停止再次請求該資源。
### 413 Request Entity Too Large
該狀態(tài)碼表示服務(wù)器拒絕處理當(dāng)前請求,因?yàn)樵撜埱筇峤坏膶?shí)體數(shù)據(jù)大小超過了服務(wù)器愿意或者能夠處理的范圍。
> 此種情況下,服務(wù)器可以關(guān)閉連接以免客戶端繼續(xù)發(fā)送此請求。
如果這個(gè)狀況是臨時(shí)的,服務(wù)器 `應(yīng)該` 返回一個(gè) `Retry-After` 的響應(yīng)頭,以告知客戶端可以在多少時(shí)間以后重新嘗試。
### 414 Request-URI Too Long
該狀態(tài)碼表示請求的 `URI` 長度超過了服務(wù)器能夠解釋的長度,因此服務(wù)器拒絕對該請求提供服務(wù)。
### 415 Unsupported Media Type
通常表示服務(wù)器不支持客戶端請求首部 `Content-Type` 指定的數(shù)據(jù)格式。如在只接受 `JSON` 格式的 `API` 中放入 `XML` 類型的數(shù)據(jù)并向服務(wù)器發(fā)送,都 `應(yīng)該` 返回該狀態(tài)碼。
該狀態(tài)碼也可用于如:只允許上傳圖片格式的文件,但是客戶端提交媒體文件非法或不是圖片類型,這時(shí) `應(yīng)該`返回該狀態(tài)碼:
“`
HTTP/1.1 415 Unsupported Media Type
Server: nginx/1.11.9
Content-Type: application/json
Transfer-Encoding: chunked
Cache-Control: no-cache, private
Date: Sun, 24 Jun 2018 12:09:40 GMT
Connection: keep-alive
{“error_code”:41500,”message”:”不允許上傳的圖片格式”}
“`
### 429 Too Many Request
該狀態(tài)碼表示用戶請求次數(shù)超過允許范圍。如 `API` 設(shè)定為 `60次/分鐘`,當(dāng)用戶在一分鐘內(nèi)請求次數(shù)超過 60 次后,都 `應(yīng)該` 返回該狀態(tài)碼。并且也 `應(yīng)該` 在響應(yīng)首部中加上下列頭部:
“`
X-RateLimit-Limit: 10 請求速率(由應(yīng)用設(shè)定,其單位一般為小時(shí)/分鐘等,這里是 10次/5分鐘)
X-RateLimit-Remaining: 0 當(dāng)前剩余的請求數(shù)量
X-RateLimit-Reset: 1529839462 重置時(shí)間
Retry-After: 120 下一次訪問應(yīng)該等待的時(shí)間(秒)
“`
列子
“`
HTTP/1.1 429 Too Many Requests
Server: nginx/1.11.9
Content-Type: application/json
Transfer-Encoding: chunked
X-RateLimit-Limit: 10
X-RateLimit-Remaining: 0
X-RateLimit-Reset: 1529839462
Retry-After: 290
Cache-Control: no-cache, private
Date: Sun, 24 Jun 2018 11:19:32 GMT
Connection: keep-alive
{“message”:”You have exceeded your rate limit.”,”error_code”:42900}
“`
`必須` 為所有的 API 設(shè)置 Rate Limit 支持。
### 500 Internal Server Error
該狀態(tài)碼 `必須` 在服務(wù)器出錯(cuò)時(shí)拋出,對于所有的 `500` 錯(cuò)誤,都 `應(yīng)該` 提供完整的錯(cuò)誤信息支持,也方便跟蹤調(diào)試。
### 503 Service Unavailable
該狀態(tài)碼表示服務(wù)器暫時(shí)處理不可用狀態(tài),當(dāng)服務(wù)器需要維護(hù)或第三方 `API` 請求超時(shí)/不可達(dá)時(shí),都 `應(yīng)該` 返回該狀態(tài)碼,其中若是主動(dòng)關(guān)閉 API 服務(wù),`應(yīng)該`在返回的響應(yīng)首部加上 `Retry-After` 頭部,表示多少秒后可以再次訪問。
“`
HTTP/1.1 503 Service Unavailable
Server: nginx/1.11.9
Content-Type: application/json
Transfer-Encoding: chunked
Cache-Control: no-cache, private
Date: Sun, 24 Jun 2018 10:56:20 GMT
Retry-After: 60
Connection: keep-alive
{“error_code”:50300,”message”:”服務(wù)維護(hù)中”}
“`
其他 `HTTP` 狀態(tài)碼請參考 HTTP 狀態(tài)碼- 維基百科。
## 參考資料
原文: 《[RESTful 設(shè)計(jì)規(guī)范](https://godruoyi.com/posts/the-resetful-api-design-specification)》
[HTTP 狀態(tài)碼- 維基百科](https://zh.wikipedia.org/zh-hans/HTTP%E7%8A%B6%E6%80%81%E7%A0%81)