如何創建RESTFul Web服務
想寫這篇文章很久了,這是個大話題,不是一時半會就能說清楚的。 所以準備花個一星期整理資料,把思路理清楚,然後再在Team裏做個sharing:)
其實RESTFul是架構風格,並不是實現規範,也不一定非要用HTTP,但鑒於HTTP的普世性和 SOA的實現基本都基於HTTP實現。 這句話隻對了前一半, 實際上REST和HTTP是息息相關的,是一種Web架構,WWW是世界最大型的分布式應用,而其實現就是基於REST的web架構的設計標準,REST架構的提出者(Roy T. Fielding 2000年在他的博士論文中提出REST的架構風格),Roy 本身也是web標準(URI, HTTP, HTML) 的製定者,以及Web Server (Apache)的實現者,並且一直用REST的思想指導著標準製定,可以說HTTP就是該架構風格的一個典型應用,所以提到REST,就默認是用HTTP作為通信協議了。
一、HTTP 協議
2. Status Code
4. 中文掃盲
二、什麼是REST
REST關鍵原則
三、REST開發指導
A very nice article of REST:
https://rest.elkstein.org/2008/02/what-is-rest.html
How to impl REST:
https://www.infoq.com/cn/articles/RESTSOAFuture
什麼是好的RESTful API?
1. 這個API應該是對瀏覽器友好的,能夠很好地融入web,而不是與web格格不入,好的RESTful API應該能夠使用瀏覽器+HTML完成所有的測試。
2. API中所包含的資源和對資源的操作,應該是直觀和容易理解的,並且符合HTTP協議的要求。
3.API應該是鬆耦合的。(有待進一步理解)
REST的耦合度比SOAP更低,因為SOAP實現仍是基於RPC調用方式,RPC方式是緊密耦合的表現;而緊密耦合的係統是無法適應Web級的規模可伸縮性的。REST Web服務則繼承了Web鬆散耦合的特點,客戶應用通過邏輯URL訪問服務,服務的實現對客戶來說是完全透明的,客戶程序可以對服務的實現技術、方法毫無所知。
4.API中所有的格式應該是常見的通用格式,常見的有HTML、XML、JSON,常見的格式處理起來非常容易,有大量的框架和庫提供支持。
5. 使用HTTP狀態碼來表達各種出錯情況。如果一個所謂的”RESTful API“對任何請求都返回200 OK的響應,在響應的消息體中返回出錯情況信息,這種做法顯然不符合”確保操作語義的可見性“這個REST架構風格的基本要求。
6. 這個API應該對HTTP緩存是友好的
HTTP協議是個分層的架構,從兩端的User agent(瀏覽器)到Origin server(Apache 服務器)之間,可以插入很多中間組件。在整個HTTP通信鏈條的很多位置,都可以設置緩存 。最常見的是瀏覽器緩存和服務器緩存:
瀏覽器端,下載一個類似HTTP watch的瀏覽器插件,就能很容易觀察到對一個網站的進行第二次訪問時,很多信息如圖片,JS,JSS都是從瀏覽器緩存中取得,而不是去服務器取,節省了很多網絡開銷,也減輕了服務器壓力。
在服務器端,也有很多緩存技術,可以參見這篇文章Caching your REST API來了解一種典型的服務器緩存技術,大概意思就是在對資源執行安全的操作如GET時,將response放入緩存,當對資源進行不安全操作如PUT/DELETE,將該response從緩存中移除(PURGE)出去,這樣保證客戶端不會得到過期的response。
在使用緩存時,不管是在客戶端還是服務器端,一個非常重要的原則就是就語義透明性(Semantic Transparency)。
什麼是緩存的語義透明性?就是不管在客戶端還是服務器端使用緩存,對一個請求來說,其使用緩存得到的響應(Response)和直接訪問服務器(Origin Server)所得到響應結果,應該是一模一樣的,沒有任何差別,緩存對服務的訪問者來說應該是透明的。
完全達到語義透明性隻是一個理想狀態,Web是鬆耦合的,所以弱一致性(Weak consistency) 是基於Web的分布式應用的特點,但是我們可以通過一些手段來增強一致性,盡量達到語義透明性。常用的方式有失效、驗證、過期。
如何對RESTful API進行版本控製?
一個比較簡單實用的做法是直接在URI中插入版本號,這樣做允許多個版本的API並行運行。另一個做法是在HTTP請求中加入自定義頭信息,標明使用的版本號。不過這個做法其實對瀏覽器不夠友好,簡單地使用瀏覽器+HTML無法測試。
還有對於微小改動,最好可以做到向後兼容而不改變版本號,最關鍵的就是在擴展時不能破壞現有的客戶端,例如,變更一個參數,可以選擇同時兼容新舊兩種輸入,或者保持老參數不動,提供一個新參數,在文檔中必須做出說明,不推薦新用戶繼續使用之前的參數。
HTTP1.1規範中給出的動詞對於設計RESTful API 夠用嗎?
如果資源抽象做的很好,對於某個資源的任何操作,通常都能夠映射到CRUD四個類別中。CRUD四個類別對於操作資源來說,絕大多數情況下是完備的。HTTP的四個方法對CRUD的映射關係是Create-POST, Retrieve-GET, Update-PUT, Delete-DELETE。如果在資源上定義的操作過多,往往這個資源可以拆分出更多的資源。
關於API的冪等性
冪等性是係統接口對外部調用的承諾,承諾隻要調用接口成功,外部多次調用對係統影響是一致的。冪等性的好處是,外部在調用係統失敗後,在進行重試時,無需更改請求內容。
在大規模分布式係統中,完成一個功能,需要很多服務或者組件的協作,通常我們會用一個uniqueRequestId or dedupeId 來標識一次請求的唯一性,而在調用服務出錯時,如網絡超時,係統內部錯誤,一般都要進行重試,冪等的接口允許重試時,使用相同的dedupeId。而非冪等的接口可能需要更改dedupeId來和上一次請求做區分,增加了客戶端使用服務的負擔。
所以在我看來,不僅GET/DELETE需要時冪等的,所有的REST API都應該盡量做到冪等,包括POST/PUT。比如在eLedger係統裏,創建journal entry(流水賬)是最常用的API,如果客戶POST兩次一模一樣的請求(最主要是dedupeId一樣),eLedger每次都會返回成功的結果,隻不過在第二個POST到來時,係統檢測到流水已經被創建,並不會創建新的流水,隻是將已創建的結果返回給客戶端,從某種意義上,減輕了客戶使用eLedger服務的難度,因為其不用擔心因為重複POST所造成的數據不一致。
關於REST的安全性
REST對安全性並沒有像基於WSDL,SOAP的Web Service的WS-Security的安全規範,主要取決於REST service自己的實現,因為REST是架設在HTTP之上的,所以在底層通信(TCP)使用SSL是自然而然的,SSL基本可以解決中間人(man in middle) 和 重放攻擊(replay attack)等安全問題,那麼對於應用層,所要解決的就是認證(authentication),授權(authorization),訪問(access)的問題了,鑒於可擴展性和開放性的考慮,使用OAuth是一個比較好的選擇,首先OAuth是W3C的標準規範,提供了統一的標準和規範,降低了客戶端的學習成本,其次是它把真個驗證流程劃分為認證、授權、訪問三個步驟,不僅能滿足傳統的Client-Server驗證,還具備非常良好的可擴展性,使得地方
如何定義Resource
REST開發又被稱作“麵向資源的開發”,這說明對於資源的抽象,是設計RESTful API的核心內容。RESTful API建模的過程與麵向對象建模類似,是以名詞為核心的。這些名詞就是資源,任何可命名的抽象概念都可以定義為一個資源。而HTTP協議並不是一種傳輸協議,它實際提供了一個操作資源的統一接口。利用有限的幾個方法(GET/POST/PUT/DELETE)來達到資源在不同表述狀態(REpresentationalState)之間的轉移(Transfer),這也是REST名稱的由來。 所以RESTful API建模的過程,可以看作是具有統一接口約束的麵向對象建模過程。
如果發現資源上的操作過多,以至於HTTP的方法不夠用,應該考慮設計出更多的資源。設計出更多資源(以及相應的URI)對於RESTful API來說並沒有什麼害處。
五、REST 的成熟度模型(Maturity Model)

https://martinfowler.com/articles/richardsonMaturityModel.html
最後更新:2017-04-03 16:49:04