{
“status”: “success”,
“data”: {}
}
“`
盡管HTTP狀態(tài)碼返回`200 OK`,但我不能完全確定它有沒有處理我的請求失敗。
實際上,[API](http://m.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è)計規(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”: “該活動不存在”,
}
“`
下表列舉了常見的 `HTTP` 狀態(tài)碼
| 狀態(tài)碼 | 描述 |
| — | — |
| 1xx | 代表請求已被接受,需要繼續(xù)處理 |
| 2xx | 請求已成功,請求所希望的響應(yīng)頭或數(shù)據(jù)體將隨此響應(yīng)返回 |
| 3xx | 重定向 |
| 4xx | 客戶端原因引起的錯誤 |
| 5xx | 服務(wù)端原因引起的錯誤 |
> 只有來自客戶端的請求被正確的處理后才能返回 `2xx` 的響應(yīng),所以當 API 返回 `2xx` 類型的狀態(tài)碼時,前端 `必須` 認定該請求已處理成功。
必須強調(diào)的是,所有 `API“一定不可` 返回 `1xx` 類型的狀態(tài)碼。當 `API` 發(fā)生錯誤時,`必須` 返回出錯時的詳細信息。目前常見返回錯誤信息的方法有兩種:
1、將錯誤詳細放入 `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)實體中;
“`
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”}
“`
考慮到易讀性和客戶端的易處理性,我們 `必須` 把錯誤信息直接放到響應(yīng)實體中,并且錯誤格式 `應(yīng)該` 滿足如下格式:
“`
{
“message”: “您查找的資源不存在”,
“error_code”: 404001
}
“`
其中錯誤碼(`error_code`)`必須` 和 `HTTP` 狀態(tài)碼對應(yīng),也方便錯誤碼歸類,如:
“`
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)該` 在返回的錯誤信息中,同時包含面向開發(fā)者和面向用戶的提示信息,前者可方便開發(fā)人員調(diào)試,后者可直接展示給終端用戶查看如:
“`
{
“message”: “直接展示給終端用戶的錯誤信息”,
“error_code”: “業(yè)務(wù)錯誤碼”,
“error”: “供開發(fā)者查看的錯誤信息”,
“debug”: [
“錯誤堆棧,必須開啟 debug 才存在”
]
}
“`
下面詳細列舉了各種情況 API 的返回說明。
### 200 ok
`200` 狀態(tài)碼是最常見的 `HTTP` 狀態(tài)碼,在所有 __成功__ 的 `GET` 請求中,`必須` 返回此狀態(tài)碼。`HTTP` 響應(yīng)實體部分 `必須` 直接就是數(shù)據(jù),不要做多余的包裝。
錯誤示例:
“`
HTTP/1.1 200 ok
Content-Type: application/json
Server: example.com
{
“user”: {
“id”:1,
“nickname”:”fwest”,
“username”: “example”
}
}
“`
正確示例:
1、獲取單個資源詳情
“`
{
“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
當服務(wù)器創(chuàng)建數(shù)據(jù)成功時,`應(yīng)該` 返回此狀態(tài)碼。常見的應(yīng)用場景是使用 `POST` 提交用戶信息,如:
– 添加了新用戶
– 上傳了圖片
– 創(chuà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”
}
“`
也可以返回一個響應(yīng)實體為空的 `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)該` 采用第二種方式,因為大多數(shù)情況下,客戶端只需要知道該請求操作成功與否,并不需要返回新資源的信息。
### 202 Accepted
該狀態(tài)碼表示服務(wù)器已經(jīng)接受到了來自客戶端的請求,但還未開始處理。常用短信發(fā)送、郵件通知、模板消息推送等這類很耗時需要隊列支持的場景中;
> 返回該狀態(tài)碼時,響應(yīng)實體 `必須` 為空。
“`
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ù)據(jù),其中:
– 在使用 `DELETE` 方法刪除資源 __成功__ 時,`必須` 返回該狀態(tài)碼
– 使用 `PUT`、`PATCH` 方法更新數(shù)據(jù) __成功__ 時,也 `應(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)碼。因為 `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);若一定要使用重定向功能,`可以` 返回一個響應(yīng)實體為空的 `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
由于明顯的客戶端錯誤(例如,請求語法格式錯誤、無效的請求、無效的簽名等),服務(wù)器 `應(yīng)該` 放棄該請求。
> 當服務(wù)器無法從其他 4xx 類型的狀態(tài)碼中找出合適的來表示錯誤類型時,都 `必須` 返回該狀態(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)碼表示當前請求需要身份認證,以下情況都 `必須` 返回該狀態(tài)碼。
– 未認證用戶訪問需要認證的 API
– access_token 無效/過期
> 客戶端在收到 `401` 響應(yīng)后,都 `應(yīng)該` 提示用戶進行下一步的登錄操作。
“`
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ù)。
如當普通用戶請求操作管理員用戶時,`必須` 返回該狀態(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)
– 訪問不存在的端點
都 `必須` 返回該狀態(tài)碼,若該資源已永久不存在,則 `應(yīng)該` 返回 `401` 響應(yīng)。
### 405 Method Not Allowd
當客戶端使用的 `HTTP` 請求方法不被服務(wù)器允許時,`必須` 返回該狀態(tài)碼。
> 如客戶端調(diào)用了 `POST` 方法來訪問只支持 GET 方法的 API
該響應(yīng) `必須` 返回一個 `Allow` 頭信息用以表示出當前資源能夠接受的請求方法的列表。
“`
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ù)格式時,應(yīng)該返回此狀態(tài)碼。如支持 `JSON` 和 `XML` 輸出的 `API` 被指定返回 `YAML` 格式的數(shù)據(jù)時。
> Http 協(xié)議一般通過請求首部的 Accept 來指定數(shù)據(jù)格式
### 408 Request Timeout
客戶端請求超時時 `必須` 返回該狀態(tài)碼,需要注意的時,該狀態(tài)碼表示 __客戶端請求超時__,在涉及第三方 `API`調(diào)用超時時,`一定不可` 返回該狀態(tài)碼。
### 409 Gonfilct
該狀態(tài)碼表示因為請求存在沖突無法處理。如通過手機號碼提供注冊功能的 `API`,當用戶提交的手機號已存在時,`必須` 返回此狀態(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”:”手機號已存在”}
“`
### 410 Gone
和 `404` 類似,該狀態(tài)碼也表示請求的資源不存在,只是 `410` 狀態(tài)碼進一步表示所請求的資源已不存在,并且未來也不會存在。在收到 `410` 狀態(tài)碼后,客戶端 `應(yīng)該` 停止再次請求該資源。
### 413 Request Entity Too Large
該狀態(tài)碼表示服務(wù)器拒絕處理當前請求,因為該請求提交的實體數(shù)據(jù)大小超過了服務(wù)器愿意或者能夠處理的范圍。
> 此種情況下,服務(wù)器可以關(guān)閉連接以免客戶端繼續(xù)發(fā)送此請求。
如果這個狀況是臨時的,服務(wù)器 `應(yīng)該` 返回一個 `Retry-After` 的響應(yīng)頭,以告知客戶端可以在多少時間以后重新嘗試。
### 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)碼也可用于如:只允許上傳圖片格式的文件,但是客戶端提交媒體文件非法或不是圖片類型,這時 `應(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次/分鐘`,當用戶在一分鐘內(nèi)請求次數(shù)超過 60 次后,都 `應(yīng)該` 返回該狀態(tài)碼。并且也 `應(yīng)該` 在響應(yīng)首部中加上下列頭部:
“`
X-RateLimit-Limit: 10 請求速率(由應(yīng)用設(shè)定,其單位一般為小時/分鐘等,這里是 10次/5分鐘)
X-RateLimit-Remaining: 0 當前剩余的請求數(shù)量
X-RateLimit-Reset: 1529839462 重置時間
Retry-After: 120 下一次訪問應(yīng)該等待的時間(秒)
“`
列子
“`
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ù)器出錯時拋出,對于所有的 `500` 錯誤,都 `應(yīng)該` 提供完整的錯誤信息支持,也方便跟蹤調(diào)試。
### 503 Service Unavailable
該狀態(tài)碼表示服務(wù)器暫時處理不可用狀態(tài),當服務(wù)器需要維護或第三方 `API` 請求超時/不可達時,都 `應(yīng)該` 返回該狀態(tài)碼,其中若是主動關(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ù)維護中”}
“`
其他 `HTTP` 狀態(tài)碼請參考 HTTP 狀態(tài)碼- 維基百科。
## 參考資料
原文: 《[RESTful 設(shè)計規(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)