前言
最近我司要制定開發規范。在討論接口返回的時候,后端的同事詢問我們前端,錯誤信息的返回,前端有什么意見?
所以做了一些調研給到后端的同事做參考。
錯誤信息返回
在使用API時無可避免地會因為各種情況而導致接口返回錯誤的信息。比如指定的query參數錯誤,又或者method不支持等,這些情況都會返回相關的錯誤信息。另外服務器不穩定或者停止運行了,也必須將錯誤信息返回。
顯然,當錯誤發生的時候,只是籠統地返回“發生了錯誤”是不行的。如果前端不了解發生了什么錯誤,也就不知道該怎么去調試,怎么去修復這個bug。所以說,必須向前端返回盡可能多的信息,以便前端找到出錯的地方解決問題。
通過HTTP狀態碼表示出錯信息
首先必須選擇合適的HTTP狀態碼,之前我司的后端API沒有遵循這個規則。例如API無論如何訪問,都會返回200狀態碼,只在返回消息體中的描述是否發生錯誤。
HTTP/1.1 200 OK Content-Type: application/json { "error": { "code": 2002, "message": "Invalid parameter" } }
雖然這么處理前端也能理解API的錯誤信息,但由於HTTP協議已經完整地定義了各個狀態碼所表示的含義,所以返回恰當的狀態碼才能提高前端正確識別錯誤的可能性。
如果出錯了,仍然返回200狀態碼,有可能導致前端的處理發生混亂,這種情況要一定要禁止。特別是通用的API,基本上都是先看狀態碼再決定下一步的處理,如果沒有返回正確的狀態碼,就會導致前端無法執行適當的方法去處理,從而引發各種不必要的問題。而且這種做法沒有盡可能地運用HTTP協議,也給前端編寫錯誤處理增加了難度。
- 狀態碼分類
| 狀態碼 | 含義 |
|---|---|
| 1xx | 消息 |
| 2xx | 成功 |
| 3xx | 重定向 |
| 4xx | 前端原因引起的錯誤 |
| 5xx | 服務器原因引起的錯誤 |
下面主要來了解一下4xx和5xx的錯誤碼:
4xx-前端發生了錯誤
4xx的狀態碼主要是用於描述因前端請求的問題而引發的錯誤,也就是說服務器端不存在出錯問題,但服務器端無法理解前端的請求,或者能理解但無法處理的請求。這一類的錯誤,統一使用4xx錯誤碼。
| 狀態碼 | 名稱 | 說明 |
|---|---|---|
| 400 | Bad Request | 表示其他錯誤,就是4xx都無法描述的前端發生的錯誤 |
| 401 | Authentication | 表示認證類型的錯誤 |
| 403 | Authorization | 表示授權的錯誤(認證和授權的區別在於:認證表示“識別前來訪問的是誰”,而授權則是“賦予特定用戶執行特定操作的權限”) |
| 404 | Not Found | 表示訪問的數據不存在 |
| 405 | Method Not Allowd | 表示可以訪問接口,但是使用的HTTP方法不允許 |
| 406 | Not Acceptable | 表示API不支持前端指定的數據格式 |
| 408 | Request Timeout | 表示前端發送的請求到服務器所需的時間太長 |
| 409 | Confilct | 表示資源發生了沖突,比如使用已被注冊郵箱地址注冊時,就引起沖突 |
| 410 | Gone | 表示訪問的資源不存在。不單表示資源不存在,還進一步告知該資源該資源曾經存在但目前已消失 |
| 413 | Request Entity Too Large | 表示請求的消息體過長而引發的錯誤 |
| 414 | Request-URI Too Large | 表示請求的首部過長而引發的錯誤 |
| 415 | Unsupported Media Type | 表示服務器端不支持客戶端請求首部Content-Type里指定的數據格式 |
| 416 | Range Not Satisfiable | 表示無法提供Range請求中的指定的那段包體 |
| 417 | Expectation Failed | 表示對於Expect請求頭部期待的情況無法滿足時的響應碼 |
| 421 | Misdirected Request | 表示服務器認為這個請求不該發給它,因為它沒能力處理 |
| 426 | Upgrade Required | 表示服務器拒絕基於當前HTTP協議提供服務,通過Upgrade頭部告知客戶端必須升級協議才能繼續處理 |
| 428 | Precondition Required | 表示用戶請求中缺失了條件類頭部,例如If-Match |
| 429 | Too Many Requests | 表示客戶端發送請求的速率過快 |
| 431 | Request Header Fields Too Large | 表示請求的HEADER頭部大小超出限制 |
| 451 | Unavailable For Legal Reasons | 表示由於法律原因不可訪問 |
5xx-服務器端發生錯誤
5xx狀態碼表示錯誤由服務器端的問題引發的。
| 狀態碼 | 名稱 | 說明 |
|---|---|---|
| 500 | Internal Server Error | 表示服務器內部錯誤,且不屬於以下錯誤類型 |
| 501 | Not Implemented | 表示服務器不支持實現請求所需要的功能 |
| 502 | Bad Gateway | 代理服務器無法獲取到合法資源 |
| 503 | Service Unavailable | 服務器資源尚未准備好處理當前請求 |
| 504 | Gateway Timeout | 表示代理服務器無法及時的從上游獲得響應 |
| 505 | HTTP Verson Not Supported | 表示請求使用的HTTP協議版本不支持 |
| 507 | Insufficient Storage | 表示服務器沒有足夠的空間處理請求 |
| 508 | Loop Detected | 表示訪問資源時檢測到循環 |
| 511 | Network Authentication Required | 表示代理服務器發現客戶端需要進行身份驗證才能獲得網絡訪問權限 |
向前端返回詳細的錯誤信息
當錯誤發生時,除了需要返回相應的狀態碼之外,還需要返回詳情的錯誤信息。因為狀態碼只是通用的描述錯誤的類別,一般無法表示實際發生的具體錯誤信息。
比如說400狀態碼,只是知道前端請求發生了錯誤,至於如何去修改,僅憑這個是沒有辦法找到bug的。
通常來說:返回錯誤信息的方法有兩種:
- 將信息放入
HTTP響應頭 - 將信息通過
HTTP響應體返回
1、通過自定義頭部,將詳細的錯誤信息放入響應頭中
X-ERROR-CODE: 2020 X-ERROR-MESSAGE: Bad authentication token X-ERROR-INFO: http://api.example.com/v1/authentication
2、將錯誤信息放入響應體中
{ "error": { "code": 2020, "message": "Bad authentication token", "info": "http://api.example.com/v1/authentication" } }
從前端的角度來考慮,通過響應體返回會更加容易處理。
這里的錯誤代碼的命名方式,按照后端自己的要求編寫即可。
通常情況下,會要求接口的錯誤信息越詳細越好,但這也不是一定的,也會有特殊情況。
一般而言,前端會將后端接口的錯誤信息原封不動的顯示出來,因為前端很難去判斷是否有涉密信息或者讓用戶難堪的信息。比如說A用戶屏蔽了B用戶,當B用戶想看A用戶的詳情時,如果正確的返回:“A用戶已屏蔽B用戶,無法獲取”的話,會讓雙方都難堪。這時就需要返回模棱兩可的信息。這個就需要后端開發們自己去領悟。
針對默認返回與API維護
某些接口在發生錯誤時會將HTML返回。特別是發生404、503等錯誤時,這種情況就比較常見。當發生這些錯誤時,用於構建API的Web服務器或者app框架會直接返回出錯信息,默認情況下大都是HTML。
但雖說是發生了錯誤,前端依然在訪問中,所以仍然期待服務器返回約定好的格式,比如JSON。尤其在通過Accept請求頭部或擴展名等指定了接收格式時。當然可以讓前端去檢查Content_Type頭部,進行相應的處理。但如果前端處理的不好或者沒有處理,可能會導致app崩潰。
尤其是公共api,不能期望所有的使用者都嚴格遵循規范來處理好,這種api算不上了好的api。
關於API的維護,正常來說,要避免不得不停止API的發生。但特殊的時候也會不得不停止API進行維護工作,這種情況需要返回503狀態碼來告知前端當前API已經停止工作。另外,因為這種停止操作不是意外而是有計划進行的,所以要有API何時重啟的時間信息,將其發送給前端。
不僅要預備好用於定期維護的狀態碼和出錯信息的返回,還要使用Retry-After頭部來告訴前端維護結束的時間。從SEO的角度來看,這個方式對普通的web站點的維護也同樣適用,也是Google推薦的方法。
Retry-After的值可以是某個具體的日期或從當前時刻算起至可正常訪問為止所需的秒數。
503 Service Temporarily Unavailable
Retry-After: Mon, 9 Sep 2020 20:00:00 GMT
從前端實現的角度來看,在返回503錯誤時,是期待前端能識別出API地方Retry-After值指定的時間等待,然后在API重啟的時候再次訪問。
雖然這些處理都取決於前端的具體實現,后端無法對此進行控制,但依然要盡可能地返回詳細的信息,方便前端處理並提升用戶體驗。
總結
主要是三個痛點:
- 必須選擇合適的
HTTP狀態碼 - 向前端返回詳細的錯誤信息
- 針對默認返回與
API維護
作者: zhangwinwin
鏈接:后端API接口的錯誤信息返回規范
來源:github
