2015年冬天,我寫下第一篇也是目前惟一一篇關於 Restful API 設計的文章。時間過的飛快,轉眼三年前過去了。這三年間經歷過的項目中,後臺逐漸微服務化,restful 也成爲你們耳熟能詳的設計方案。這裏記下些本身的經驗和教訓,以供對照。數據庫
基本的 code 原則很簡單,2xx 表示成功,4xx 表示客戶端錯誤,5xx 表示服務端錯誤。數組
那如何分辨是客戶端仍是服務端錯誤呢?我總結了如下幾種常見的客戶端錯誤,以及對應的錯誤碼。restful
總之,凡是客戶的鍋,都返回 4xx 。若是剛好不在上面所列的三種狀況中,則用 400 代替。微服務
服務端自身錯誤則包含兩類狀況:測試
第一種錯誤是不可避免的,屬於不可控的外部環境問題。第二種錯誤雖然能夠經過 review 代碼加上各類測試來預防,但最好有個兜底的錯誤處理以避免程序掛掉。ui
我司對於服務端錯誤統一返回 500(internal server error),由於考慮到服務端錯誤對於客戶來說毫無建設意義,畢竟客戶絕對沒有辦法幫助咱們解決錯誤。即便對於工程師來講,日誌也比 code 更有表現力。相對而言,客戶端錯誤則儘可能設計的詳細由於大部分狀況下客戶端要據此來引導用戶回到正常的業務中來。好比,若是返回 401,則引導用戶登錄或者註冊。若是業務比較複雜,還要考慮擴展 reponse 來指明更加具體的錯誤。如:設計
400 bad request { "code": 123, "message": "Name is required" }
GET /ordersrest
200 OK { "offset": 0, "limit": 20, "count": 100, "elements": [...] }
對於這個 List API,若是資源不存在,返回應該是什麼。受 404 概念的普及影響,不少人會選擇返回日誌
404 NotFound
難道說,若是不存在 orders(訂單) 就是錯誤嗎?好比我歷來沒有在淘寶下過單,那訂單列表也就應該顯示客戶端錯誤嗎?這顯然是不對的。實際上,404 是指所請求的資源不存在。而對於 orders 來講,它是一個集合概念。無論下沒下過單,這個集合總歸是存在的。按照這個理論,正確的返回應該是:code
200 OK { "offset": 0, "limit": 20, "count": 100, "elements": [] // 空數組 }
因此對於 List API 來講,沒有 404。
restful API 的路徑能夠表現資源的從屬關係。好比,用戶能夠有多個地址。
/users/{user_id}/addresses/
那麼,對於一個並不存在的用戶而言,訪問上述 API,應該返回什麼?
用戶不存在,他的地址也必然不存在,那彷佛是個簡單的客戶端錯誤。但咱們確實有必要參考 Parent resource 的狀態嗎?這從理論上講彷佛毫無破綻,但實際操做及其困難。假如 Parent resource 的狀態爲 s1, Child resource 的狀態爲 s2,若是必須參考 s1 才能定義 s2,則 Child resource 的狀態爲 s1 s2。這仍是簡單的層次,若是 Parent 之上還有 Parent,則最終 Child 的狀態會變成 s0 s1 * s2。若是隨着業務的升級,每一個節點的狀態推算都要這樣愈來愈複雜,那結果必然是整個系統的崩塌。
因此,目前比較推崇的作法是,僅僅考慮目標資源或者資源集合的狀態。即,addresses,無論它從屬於誰。