2019獨角獸企業重金招聘Python工程師標準>>>
上半年時候,部門有組織的討論了一下實踐微服務的技術話題,主要內容是SOA服務和微服務各自的優勢和難點,其中有提到關于RESTful API設計方法。
正好最近在深入的學習HTTP協議,也看了一些有關RESTful API的資料,這篇博客,就將自己的一些理解整理記錄一下。
PS:本篇博客主要談一些概要的設計思想和方法,不談具體的實現細節,如有誤差歡迎指出,謝謝!
想進一步了解RESTful API,建議學習下面列出的一些詞條:
HTTP協議、分布式系統架構原理(CAP)、操作系統原理。。。
參考資料:
跟著Github學習TESTful HTTP API設計
一種RESTful API接口的約定
RESTful API設計最佳實踐
知乎:如何用通俗易懂的語言解釋RESTful API?
?
一、REST的由來
全稱:REST,全稱是Resource Representational State Transfer,即:資源在網絡中以某種形式進行狀態轉移。————所謂狀態的轉移,可參考《HTTP權威指南》一書中對協議的詳細解釋,此處不過多贅述!
出現:REST最早是由Roy Fielding博士發表的論文中提到的,他也曾參與設計了HTTP協議。論文地址:http://www.ics.uci.edu/~fielding/pubs/dissertation/top.htm
定義:簡單來說REST是一種系統架構設計風格(而非標準),一種分布式系統的應用層解決方案。
背景:早期的網頁端是前后臺一起的,比如PHP、JSP等。而隨著近幾年移動端的快速發展和分布式架構的應用,各種Client層出不窮,這個時候就需要有個統一的機制,來為前后端通信提供服務。
? ? ?而RESTful API就是目前比較成熟的的一套應用程序API設計理論。
目的:Client和Server端進一步解耦。
應用:最為經典的莫過于github API。
?
二、RESTful的特征和優點
1、客戶端-服務器(Client-Server):提供服務的服務器和使用服務的客戶端分離解耦;
? ?優點:提高客戶端的便捷性(操作簡單)
? ? ? ? 簡化服務器提高可伸縮性(高性能、低成本)
? ? ? ? 允許客戶端服務端分組優化,彼此不受影響
2、無狀態(Stateless):來自客戶的每一個請求必須包含服務器處理該請求所需的所有信息(請求信息唯一性);
? ?優點:提高可見性(可以單獨考慮每個請求)
? ? ? ? 提高可靠性(更容易故障恢復)
? ? ? ? 提高了可擴展性(降低了服務器資源使用)
3、可緩存(Cachable):服務器必須讓客戶端知道請求是否可以被緩存?如果可以,客戶端可以重用之前的請求信息發送請求;
? ?優點:減少交互連接數
? ? ? ? 減少連接過程的網絡時延
4、分層系統(Layered System):允許服務器和客戶端之間的中間層(代理,網關等)代替服務器對客戶端的請求進行回應,而客戶端不需要關心與它交互的組件之外的事情;
? ?優點:提高了系統的可擴展性
? ? ? ? 簡化了系統的復雜性
5、統一接口(Uniform Interface):客戶和服務器之間通信的方法必須是統一化的。(例如:GET,POST,PUT.DELETE)
? ?優點:提高交互的可見性
? ? ? ? 鼓勵單獨優化改善組件
6、支持按需代碼(Code-On-Demand,可選):服務器可以提供一些代碼或者腳本并在客戶的運行環境中執行。
? ?優點:提高可擴展性
?
三、概要設計方法
1、協議
API與Client的通信協議,總是使用HTTPS協議。
PS:使用HTTPS協議和RESTful API本身沒有多大關系,但是對于增加網站的安全是非常重要的,特別是如果提供的是公開的API,那么HTTPS久更顯得重要了。
2、域名
應該盡量將API部署在專用的域名下面,比如:
?https://api.github.com?
如果API變化較大,可以把API設計為子域名,比如:
?https://example.com/api/v1?
3、版本(Versioning)
一般而言應該將API放入URL中,比如:
?https://example.com/api/v1?
還可以將版本號放入HTTP信息頭中,但這樣不如放入URL方便和直觀。
4、路徑(Endpoint)
在協議中,每個網址代表一種資源的存放地址,所以網址終不能有動詞,只能有名詞,而且名詞一般都應該與數據庫的表字段對應,且API中的名詞應該使用復數。例如:
/users/:username/repos /users/:org/repos /repos/:owner/:repo /repos/:owner/:repo/tags /repos/:owner/:repo/branches/:branch
PS:根據RFC3986定義,URL是大小寫敏感的,所以應該盡量使用小寫字母來命名!
5、方法(Method)
有了資源的URL設計,所有針對資源的操作都是使用HTTP方法指定的,常見的方法有(括號中為對應的SQL命令):
Verd | 描述 |
HEAD(SELECT) | 只獲取某個資源的頭部信息 |
GET(SELECT) | 獲取資源 |
POST(CREATE) | 創建資源 |
PATCH(UPDATE) | 更新資源的部分屬性(很少用,一般用POST代替) |
PUT(UPDATE) | 更新資源,客戶端需要提供新建資源的所有屬性 |
DELETE(DELETE) | 刪除資源 |
比如:
GET /user:列出所有的用戶POST /user:新建一個用戶PATCH /user/ID:更新某個指定用戶的信息DELETE /user/ID:刪除所有用戶
6、數據過濾(Filtering)
如果數據量太大,服務器不可能將所有數據返回給用戶。API應該提供參數(比如Query),過濾返回結果。比如:
?limit=10:指定返回記錄的數量 ?offset=10:指定返回記錄的開始位置 ?page=2&per_page=100:指定第幾頁,以及每頁的記錄數 ?sortby=name&order=asc:指定返回結果按照哪個屬性排序,以及排序順序 ?state=close:指定篩選條件
7、狀態碼
在HTTP報文構成中,有個字段很重要:status code。它說明請求的大致情況,是否正常處理、出現了什么錯誤等。狀態碼都是三位數,大概分為了一下幾個區間:
狀態碼 | 描述 |
2XX | 請求正常處理并返回 |
3XX | 重定向,請求的資源位置發生變化 |
4XX | 客戶端發送的請求有誤 |
5XX | 服務器端的錯誤 |
關于狀態碼,具體的介紹可以去我之前的博客HTTP狀態碼或者參考其他資料,這里不過多贅述。
8、錯誤處理
如果出錯的話,在response body中應通過message字段,以鍵值對的格式,給出明確的錯誤信息。
最基本的思路應該是:盡可能提供準確的錯誤信息,比如數據格式不正確、缺少某個字段......而不是直接說“請求錯誤”之類的信息。
9、Hypermedia API
Restful API的設計最好做到Hypermedia:即在返回結果中提供相關資源的鏈接,連向其他API方法,使用戶不需要查文檔也知道下一步做什么。
這樣做的好處是,用戶可以根據返回結果就能得到后續操作需要訪問的地址。
10、身份驗證
一般來說,讓任何人隨意訪問公開的 API 是不好的做法,驗證和授權是兩件事情:
驗證(Authentication):確定用戶是其申明的身份,比如提供賬戶的密碼。不然的話,任何人偽造成其他身份(比如其他用戶或者管理員)是非常危險的;
授權(Authorization):保證用戶有對請求資源特定操作的權限。比如用戶的私人信息只能自己能訪問,其他人無法看到;有些特殊的操作只能管理員可以操作,其他用戶有只讀的權限等。
如果沒有通過驗證,需要返回401 Unauthorized狀態碼,并在 body 中說明具體的錯誤信息;而沒有被授權訪問的資源操作,需要返回403 Forbidden狀態碼,還有詳細的錯誤信息。
PS:Github API 對某些用戶未被授權訪問的資源操作返回404 Not Found,目的是為了防止私有資源的泄露(比如黑客可以自動化試探用戶的私有資源,返回 403 的話,就等于告訴黑客用戶有這些私有的資源)。
11、編寫文檔
API最終是給人使用的,無論是對內還是對外,即使遵循上面提到的所有規則,API設計的很優雅,但有時候用戶還是不知道該如何使用這些提供的API。
因此,編寫清晰可讀的文檔是很必要的事情。
而且編寫文檔也可以作為產出物的一部分,以及用來做記錄,以方便查詢參考。
?
以上內容為我個人整理記錄的關于RESTful API的概要內容,感興趣的童鞋可以自行查閱其他資料,本博客不保證內容的完全正確性!