天天看點

架構風格:你真的懂REST嗎?什麼是RESTREST限制舉個例子什麼是RESTfulHATEOAS的難點參考資料

本文探讨如下幾個問題:

  • 什麼是REST
  • REST包含哪些限制
  • 什麼是RESTful
  • 純RESTful API的難點在哪裡

如果你去搜尋「什麼是REST」的話,大部分情況下,你看到的基本都是RESTful!

這類内容主要說的是:

  • 資源URL應該怎麼寫
  • 要用GET來擷取資源
  • 要用POST來建立資源
  • 要用PUT來更新資源
  • 要用DELETE來删除資源

而實際上REST并不是這些,或者說并不完全是這些!

REST全稱Representational State Transfer,出自Roy Thomas Fielding博士的博士論文《Architectural Styles and

the Design of Network-based Software Architectures》第五章(Fielding博士的這篇論文會在後面單獨讨論),一般翻譯為「表述性狀态轉移」。

在論文的第6章第一節提到了為什麼會取REST這麼一個名字:

The name 「Representational State Transfer」 is intended to evoke an image of how a well-designed Web application behaves: a network of web pages (a virtual state-machine), where the user progresses through the application by selecting links (state transitions), resulting in the next page (representing the next state of the application) being transferred to the user and rendered for their use.

「表述性狀态轉移」這個名稱是為了喚起人們對于一個良好設計的 Web 應用如何運轉的印象:一個由網頁組成的網絡(一個虛拟狀态機),使用者通過選擇連結在應用中前進(狀态遷移),導緻下一個頁面(應用的下一個狀态的表述)被轉移給使用者,并且呈現給他們,以便他們來使用。

在「

什麼是架構模式和架構風格

」一文中,提到過:

  • 架構風格是一組架構限制
  • REST是一種架構風格

是以,REST是一組架構限制!

REST限制

REST是一個複合架構風格,即它包含了其它的架構風格!

REST限制包括:CS,無狀态,分層,緩存,統一接口以及按需代碼。其中「統一接口」是REST與其它架構風格的主要差別所在!「統一接口」包括了四個子限制:資源的識别,通過表述操作資源,自描述的消息,超媒體作為應用狀态引擎!

《Architectural Styles and

the Design of Network-based Software Architectures》第五章給出了REST的完整推導過程,這裡簡單列出!

從一個沒有限制的架構(NullStyle)開始,不斷的添加限制,使此架構進化為需要的架構

Null Style:元件之間沒有顯著邊界的系統,一個沒有限制的架構

Client-Server:

  • 限制:分離關注點(用戶端接口和服務端資料存儲)
  • 優勢:用戶端和服務端可以獨立的進化。用戶端可以與多個服務端通信,服務端可以友善的伸縮
  • 劣勢:降低了性能

Stateless:

  • 限制:通信必須在本質上是無狀态的。從客戶到伺服器的每個請求都必須包含了解該請求所必需的所有資訊,不能利用任何存儲在伺服器上的上下文,會話狀态是以要全部儲存在用戶端
  • 優勢:改善可見性,監視系統不必為了确定一個請求的全部性質而去檢視該請求之外的多個請求。改善可靠性,減輕了從局部故障中恢複的任務量。改善可伸縮性,不必在多個請求之間儲存狀态,進而允許伺服器元件迅速釋放資源,并進一步簡化其實作,因為伺服器不必跨多個請求管理資源的使用。
  • 劣勢:降低網絡性能,由于不能将狀态資料儲存在伺服器上的共享上下文中,是以增加了在一系列請求中發送的重複資料(每次互動的開銷)。将應用狀态放在用戶端,降低了伺服器對于一緻的應用行為的控制。

Cache:

  • 限制:一個請求的響應中的資料被隐式地或顯式地标記為可緩存的或不可緩存的
  • 優勢:改善網絡性能。如果響應是可緩存的,那麼用戶端緩存就可以為以後的相同請求重用這個響應的資料。可部分或全部消除一些互動,進而通過減少一系列互動的平均延遲時間,來提高效率、可伸縮性和使用者可覺察的性能。
  • 劣勢:可能降低可靠性,緩存中陳舊的資料與将請求直接發送到伺服器得到的資料可能差别很大。

Uniform Interface(REST核心特征):

  • 限制:元件之間要有一個統一的接口,包括四個子限制:
    • 資源的識别(identification of resources):每個資源都有各自的辨別符。用戶端在請求時需要指定該辨別符。用戶端所擷取的是資源的表述,如HTML,XML 或 JSON 格式等。
    • 通過表述操作資源(manipulation of resources through representations):用戶端操作的是資源的表述,而不是資源本身。
    • 自描述的消息(self-descriptive messages):每條消息都包含足夠的資訊來描述如何處理該消息。
    • 超媒體作為應用狀态引擎(HATEOAS)(hypermedia as the engine of application state):用戶端通過伺服器提供的超媒體内容來了解如何操作表述,通過将對表述的操作送出到服務端,服務端來操作資源,繼而改變服務端的狀态。
  • 優勢:簡化整體架構,改善可見性,促進獨立的可進化性。
  • 劣勢:降低了效率。資訊都使用标準化的形式來轉移,而不能使用特定于應用的需求的形式。

** Layered System**:

  • 限制:通過限制元件的行為,将架構分解為若幹等級的層。
  • 優勢:通過将元件對系統的知識限制在單一層内,為整個系統的複雜性設定了邊界,并且提高了底層獨立性。使用層來封裝遺留的服務,使新的服務免受遺留用戶端的影響;通過将不常用的功能轉移到一個共享的中間元件中,進而簡化元件的實作。中間元件還能夠通過支援跨多個網絡和處理器的負載均衡,來改善系統的可伸縮性。
  • 劣勢:增加了資料處理的開銷和延遲,是以降低了使用者可覺察的性能。可以通過在中間層使用共享緩存來彌補這一缺點。

Code-On-Demand(可選):

  • 限制:一個用戶端元件知道如何通路一組資源,但不知道如何處理它們。它向一個遠端伺服器發送對于如何處理資源的代碼的請求,接收這些代碼,然後在本地執行這些代碼
  • 優勢:能夠為一個已部署的用戶端添加功能,改善了可擴充性和可配置性;當代碼能夠使它的動作适應于用戶端的環境,并在本地與使用者互動而不是通過遠端互動時,能夠得到更好的使用者可覺察性能和效率。由于伺服器将工作交給了用戶端(否則将消耗伺服器的資源),進而改善了伺服器的可伸縮性。
  • 劣勢:由于需要管理求值環境,降低了簡單性,在一些情況下可以通過簡化靜态的用戶端功能得到補償。最大的限制是由于伺服器發送代碼而不是簡單的資料,是以缺乏可見性。如果用戶端無法信任伺服器,缺乏可見性會導緻明顯的部署問題。

總結:

可能看完了推導,你還是不知道REST是什麼!下面我通過一個列子來解釋什麼是「REST」!

舉個例子

我們先看看Fielding博士為什麼要設計REST?Fielding博士在論文裡提到了,他設計REST是為了指導現代Web架構的設計與開發!基于REST,Fielding博士設計了HTTP1.1!也就是說,HTTP1.1是符合REST的!是以要搞懂REST,隻要了解HTTP1.1就可以了!

如果你做過Web應用,那麼CS,分層,無狀态,緩存應該都很好了解,這裡就不贅述了!按需代碼就是類似Flash,Applet這類Web端應用,用以擴充Web功能的!

這裡隻說一下「統一接口」這個限制!

我們就以一個簡單的HTTP請求來解釋REST!

比如你輸入www.abc.com時:

  • 你通過标示符來定位到www.abc.com網站的首頁,abc站點将首頁資源組裝成Response資訊傳回到你的浏覽器(資源的識别)
  • 傳回的内容頭裡(HTTP header),告訴了浏覽器該如何處理傳回的資訊(自描述的消息)
  • 傳回的資訊體(HTTP body),一般是HTML格式,它是你通路的首頁資源的表述,裡面包含了你能對這個表述進行的操作,比如能通路哪些連結,能送出哪些資料(超媒體作為應用狀态引擎)
  • 你點選連結後,這是對表述的操作,你根本沒有接觸到真實的資源(通過表述操作資源)
  • 服務端接收到你的請求後,将對應連結的資源組裝成Response資訊傳回(此時應用的狀态就改變了)。
  • 浏覽器接到傳回後,将頁面渲染出來,你可以進行下一步的操作。

上面解釋了什麼是「REST」!現在來解釋一下什麼是RESTful!

前面說了,REST是一組架構限制!那麼,如果一個應用滿足了REST限制,那麼我們就可以稱這個應用是RESTful的!

雖然,很多系統自稱是RESTful的,但是,實際上,絕大部分系統都不是RESTful的,或者不是完全RESTful的!Fielding博士對這個問題,發表了一篇博文,明确什麼系統才能稱為是符合我REST的!文中明确說明,系統必須滿足HATEOAS限制才能稱為是符合REST的!而HATEOAS很難實作!因為有人的參與!

為了緩解這個尴尬,Richardson 提出了「REST成熟度模型」。該模型把 REST 服務按照成熟度劃分成 4 個層次:

  • 第一個層次(Level 0)的 Web 服務隻是使用 HTTP 作為傳輸方式,實際上隻是遠端方法調用(RPC)的一種具體形式。SOAP 和 XML-RPC 都屬于此類。
  • 第二個層次(Level 1)的 Web 服務引入了資源的概念。每個資源有對應的辨別符和表述。
  • 第三個層次(Level 2)的 Web 服務使用不同的 HTTP 方法來進行不同的操作,并且使用 HTTP 狀态碼來表示不同的結果。如 HTTP GET 方法來擷取資源,HTTP DELETE 方法來删除資源。
  • 第四個層次(Level 3)的 Web 服務使用 HATEOAS。在資源的表述中包含了連結資訊。用戶端可以根據連結來發現可以執行的動作。

從上述 REST 成熟度模型中可以看到,使用 HATEOAS 的 REST 服務是成熟度最高的,也是推薦的做法。

  • 對于不使用 HATEOAS 的 REST 服務,用戶端和伺服器的實作之間是緊密耦合的。用戶端需要根據伺服器提供的相關文檔來了解所暴露的資源和對應的操作。當伺服器發生了變化時,如修改了資源的 URI,用戶端也需要進行相應的修改。
  • 而使用 HATEOAS 的 REST 服務中,用戶端可以通過伺服器提供的資源的表達來智能地發現可以執行的操作。當伺服器發生了變化時,用戶端并不需要做出修改,因為資源的 URI 和其他資訊都是動态發現的。

現在大部分的自稱是RESTful的系統,一般隻能達到第三個層次!

HATEOAS的難點

HATEOAS為什麼難以實作?是因為用戶端無法決策!HTTP能實作RESTful,是因為浏覽器隻是将表述以及對資源的操作選項展示了出來,至于具體該如何操作,是由使用浏覽器的人來決定的!也就是說,雖然服務端告訴了用戶端操作的可選項,但是用戶端沒辦法知道該選擇什麼!

網頁浏覽是有人的參與的,但是RESTful API是沒有人參與的,這就導緻RESTful API的用戶端難以做出決定,該做什麼!

可行的解決辦法是:

  • 語義分析:用戶端具有語義分析能力,能夠自動的分析出後面需要執行哪個操作,目前這個很難實作
  • 用戶端領域設計:用戶端引入領域設計,在一個領域内,用戶端和服務端達成共識,在特定領域内,目前有哪些操作。不過這個還是做不到隻修改服務端就可以實作系統的進化。服務端進化後,用戶端需要做對應的調整才可以完成整個系統的進化。

參考資料