一、來源
- REST:Representational State Transfer (表象層狀態轉變)
- 每一個URL代表一個資源
- 客戶端和服務器之間,傳遞這種資源的某個表現層
- 客戶端通過四個HTTP動詞(get、post、put、delete),對服務器資源進行操作,實現“表現層狀態轉化”
二、六大原則
1. C-S架構
- 數據的存儲在Server端,Client端只需要使用就行。兩端徹底分離的好處使Client端代碼的可移植性變強,Server端的拓展性變強。兩端單獨開發,互不干擾
2. 無狀態性
- http請求本身就是無狀態的,基於C-S架構,客戶端的每一次請求帶有充分的信息能夠讓服務端識別。請求所需的一些信息都包含在URL的查詢參數、header、body,服務端能夠根據請求的各種參數,無需保存客戶端的狀態,將響應正確返回給客戶端。無狀態的特徵大大提高了服務端的健壯性和可擴展性
- 無狀態性也存在一點缺陷,客戶端每次請求都必須帶上相同重複的信息確定自己的身份和狀態,造成傳輸數據的冗餘性,但這種確定對於性能和使用來說,幾乎可以忽略不計
3. 統一的接口
- REST架構的核心是統一的接口。客戶端只需要關注實現接口就可以,接口的可讀性加強,使用人員方便調用
4. 一致的數據格式
- 服務端返回的數據格式要麼是xml,要麼是json,或者直接返回狀態碼。
- 每一項數據都應該具備自我描述的信息,方便代碼處理和解析其中的內容。比如:通過http返回的數據裏有[MIME type]信息,從這個信息可以知道數據的具體格式。
5. 系統分層
- 客戶端通常無法表明自己是直接還是間接與端服務器進行連接,分層是同樣要考慮安全策略
6. 可緩存
- 在萬維網上,客戶端可以緩存頁面的響應內容。因此響應都應隱式或顯式的定義爲可緩存的,若不可緩存要避免客戶端在多次請求後舊數據或髒數據來響應。管理得當的緩存會部分地或完全地除去客戶端與服務端的交互,進一步改善性能和延展性。
7. 按需編碼、可定製代碼(可選)
- 服務端可選擇臨時給客戶端下發一些功能代碼讓客戶端來執行,從而定製和擴展客戶端的某些功能。比如服務端可以返回一些 Javascript 代碼讓客戶端執行,去實現某些特定的功能。
提示:REST架構中的設計準則中,只有按需編碼爲可選項。如果某個服務違反了其他任意一項準則,嚴格意思上不能稱之爲RESTful風格。
三、RESTful的7個最佳實踐
1. 版本
- 將版本直接放到URL中,簡潔明瞭
https://example.com/api/v1/
2. 參數命名規範
- query parameter 採用駝峯或下劃線都可以
https://example.com/api/users/today_login 獲取今天登錄的用戶 https://example.com/api/users/today_login&sort=login_desc 獲取今天登錄的用戶並以降序排列
3. url命名規範
- API命名應該按照約定俗成的方式,簡潔明瞭。在RESTful架構中,每個url代表一種資源所以url中不能有動詞,只能有名詞,並且名詞中也應該使用複數。實現者應使用相應的Http動詞GET、POST、PUT、PATCH、DELETE、HEAD來操作這些資源即可。
不規範的的url,冗餘沒有意義,形式不固定,不同的開發者還需要了解文檔才能調用。 https://example.com/api/getallUsers GET 獲取所有用戶 https://example.com/api/getuser/1 GET 獲取標識爲1用戶信息 https://example.com/api/user/delete/1 GET/POST 刪除標識爲1用戶信息 https://example.com/api/updateUser/1 POST 更新標識爲1用戶信息 https://example.com/api/User/add POST 添加新的用戶 規範後的RESTful風格的url,形式固定,可讀性強,根據users名詞和http動詞就可以操作這些資源 https://example.com/api/users GET 獲取所有用戶信息 https://example.com/api/users/1 GET 獲取標識爲1用戶信息 https://example.com/api/users/1 DELETE 刪除標識爲1用戶信息 https://example.com/api/users/1 Patch 更新標識爲1用戶部分信息,包含在body中 https://example.com/api/users POST 添加新的用戶
4. 統一返回數據格式
- 對於合法的請求應該統一返回數據格式,以json爲例:
- code:包含一個證書類型的HTTP相應的狀態碼
- status:包含文本:“success”,"fail"或“error”。
- 狀態碼在500-599爲“fail”
- 狀態碼在400-499爲“error”
- 其餘均爲“success”
- message:當狀態值爲“fail”和“error”時有效,用於顯示錯誤信息。參照國際化標準,他可以包含信息碼或者編碼。
- data:包含響應的body。當狀態值爲“fail”和“error”時,data僅包含錯誤原因或異常名稱、或者null也可以是
成功返回的響應json格式 { "code": 200, "message": "success", "data": { "username": "123456", "age": 16, "address": "Beijing" } } 失敗返回的響應json格式 { "code": 401, "message": "error message", "data": null }
- 下面這個ApiResult的泛型類是在項目中用到的,拓展性強,使用方便。返回值使用統一的 ApiResult 或 ApiResult錯誤返回使用ApiResult.Error進行返回;成功返回,要求使用ApiResult.Ok 進行返回。
public class ApiResult: ApiResult { public new static ApiResult<T> Error(string message) { return new ApiResult<T> { Code = 1, Message = message, }; } [JsonProperty("data")] public T Data { get; set; } } public class ApiResult { public static ApiResult Error(string message) { return new ApiResult { Code = 1, Message = message, }; } public static ApiResult<T> Ok<T>(T data) { return new ApiResult<T>() { Code = 0, Message = "", Data = data }; } /// <summary> /// 0 是 正常 1 是有錯誤 /// </summary> [JsonProperty("code")] public int Code { get; set; } [JsonProperty("msg")] public string Message { get; set; } [JsonIgnore] public bool IsSuccess => Code == 0; }
5. http狀態碼
- 根據http status code就可以知道刪除、添加、修改等是否成功
- 1** 請求未成功
- 2** 請求成功、表示成功處理了請求的狀態碼
- 3** 請求被重定向、表示要完成請求,需要進一步操作。通常,這些狀態碼用來重定向
- 4** 請求錯誤這些狀態代碼出現錯誤,妨礙了服務器的處理
- 5** 服務器錯誤,表示服務器在嘗試處理請求時發生內部錯誤。這些錯誤可能是服務器本身出錯,而不是請求出錯
6. 合理使用query parameter
- 在請求數據時,客戶端經常對數據進行過濾和分頁等要求,而這些參數推薦採用HTTP Query Parameter的方式實現
比如設計一個最近登陸的所有用戶 https://example.com/api/users?recently_login_day=3 搜索用戶,並按照註冊時間降序 https://example.com/api/users?recently_login_day=3 搜索用戶,並按照註冊時間升序、活躍度降序 https://example.com/api/users?q=key&sort=create_title_asc,liveness_desc
7. 多表、多參數連接查詢如何設計URL
- 示例:
查詢一個獲取在6月份的訂單中大於500元的且用戶地址是北京,用戶年齡在22歲到40歲、購買金額降序排列的訂單列表 https://example.com/api/order?order_mouth=6&order_amount_greater=500&address_city=Beijing&sort=order_amount_desc&age_min=20&age_max=40 可以優化爲 https://example.com/api/orders/beijing/6?order_amount_greater=500&sort=order_amount_desc&age_min=22&age_max=40
- 再如博客園開放的Api獲取個人博客隨筆列表
請求方式:GET 請求地址:https://api.cnblogs.com/api/blogs/{blogApp}/posts?pageIndex={pageIndex} (ps:blogApp:博客名)