REST架構簡析(原論文整理)

0 引言

       目前,互聯網在社會中扮演的角色愈來愈重要。經過互聯網爲廣大羣衆提供服務,也是互聯網成功的關鍵。互聯網服務架構目前大多數都是基於REST架構來完成的。REST從它誕生至今,能夠說爲互聯網的繁榮作出了不可磨滅的貢獻。REST架構究竟是一種什麼樣的架構,而它爲什麼有這種魔力,這裏咱們就來刨根問底,挖掘它的內在以及潛在乎義。javascript

1 緒論

1.1 軟件架構

       軟件架構是一種軟件運行時的抽象。軟件運行的健壯性、擴展性、效率,軟件使用的簡潔性一般用來評判一種軟件好壞的標誌,也是一個軟件架構優劣的標誌。java

       軟件架構包含如下要素:組件、鏈接器和數據。node

       軟件架構設計的目標是建立具備一組架構屬性的架構,這些架構構成了系統需求的超集。程序員

       構建派生樹爲架構設計提供了一種指導機制。web

1.2 基於網絡的軟件架構

       基於網絡的軟件架構,顧名思義,它是網絡條件下提供服務的軟件的架構。算法

       關鍵利益的架構屬性包括:表現(網絡性能、用戶感知的性能、網絡效率)、可擴展性、簡單、可修改性(進化性、可擴展性、可定製性、可配置性、可重用性)、可見性、便攜性、可靠性數據庫

1.3 基於網絡的軟件架構樣式

       軟件架構樣式的分類是基於這些樣式引發的架構特性來決定的。apache

       基於網絡的軟件架構樣式包括:數據流樣式、複製樣式、分層樣式、移動代碼樣式、點對點樣式。編程

1.3.1 複製樣式

       基於複製樣式的系統經過讓多個進程提供相同的服務來提升數據的可訪問性和服務的可伸縮性。這些分散的服務器相互做用,爲客戶提供只有一個服務的錯覺。小程序

       示例: 分佈式文件系統和遠程版本控制系統。

       優點: 改善用戶感知性能、簡單性保持中立(由於複製的複雜性被容許網絡無心識組件在本地複製數據上的透明操做)。

       緩存: 緩存能夠說是複製存儲的變體

1.3.2 分層樣式

       客戶端 - 服務器樣式是基於網絡的應用程序的架構樣式中最常遇到的。提供一組服務的服務器組件偵聽對這些服務的請求。但願執行服務的客戶端組件經過鏈接器向服務器發送請求。服務器拒絕或執行請求並將響應發送回客戶端。

       客戶端 - 服務器組件以下:客戶端是一個觸發過程; 服務器是一個被動的過程。客戶端發出觸發服務器響應的請求。所以,客戶在其選擇時啓動活動; 它一般會延遲,直到其請求獲得服務。另外一方面,服務器等待發出請求而後對它們做出反應。服務器一般是非終止進程,一般爲多個客戶端提供服務。
       客戶端-服務器約束背後的主要原則的關注點分離。正確分離功能應簡化服務器組件,以提升可伸縮性。這種簡化一般採用將全部用戶界面功能移動到客戶端組件中的形式。分離還容許兩種類型的組件獨立發展,前提是接口不會改變。

       客戶端 - 服務器的基本形式不限制應用程序狀態在客戶端和服務器組件之間的分區方式。它一般由用於鏈接器實現的機制引用,例如遠程過程調用或面向消息的中間件。

       分層系統按層次結構組織,每一個層爲其上方的層提供服務,並使用其下層的服務。雖然分層系統被認爲是「純粹」的風格,但它在基於網絡的系統中的使用僅限於它與客戶端 - 服務器風格的結合,以提供分層客戶端服務器。

       分層系統經過將內層隱藏在除相鄰外層以外的全部層來減小跨多層的耦合,從而改善了可演化性和可重用性。示例包括分層通訊協議的處理,例如TCP / IP和OSI協議棧,以及硬件接口庫。分層系統的主要缺點是它們增長了數據處理的開銷和延遲,下降了用戶感知的性能。

       分層客戶端服務器將代理和網關組件添加到客戶端 - 服務器樣式。代理充當一個或多個客戶端組件的共享服務器,接收請求並將它們以可能的轉換轉發到服務器組件。網關組件彷佛是請求其服務的客戶端或代理的普通服務器,但其實是將這些請求(可能的轉換)轉發到其「內層」服務器。能夠在多個層中添加這些其餘介體組件,以向系統添加負載平衡和安全檢查等功能。

       基於分層客戶端服務器的體系結構在信息系統文獻中被稱爲雙層,三層或多層體系結構。

       示例: 遠程會話、遠程數據庫訪問。

1.3.3 移動代碼樣式

       移動代碼樣式使用移動性來動態地改變處理和數據源或結果目的地之間的距離。做爲活動配置的一部分,在體系結構級別引入了站點抽象,以便考慮不一樣組件的位置。引入位置概念使得在設計級別對組件之間的交互成本進行建模成爲可能。特別地,與涉及經過網絡的通訊的交互相比,共享相同位置的組件之間的交互被認爲具備可忽略的成本。經過改變其位置,組件能夠改善其交互的接近度和質量,下降交互成本,從而提升效率和用戶感知的性能。

       在全部移動代碼樣式中,數據元素被動態轉換爲組件。

       全部移動代碼樣式的基礎是虛擬機或解釋器風格的概念。代碼必須以某種方式執行,最好是在受控環境中,以知足安全性和可靠性問題,這正是虛擬機風格所提供的。它自己不是基於網絡的樣式,但當與客戶端 - 服務器樣式(REV和COD樣式)中的組件結合使用時,它一般會被用做這種樣式。
       示例:

  • 遠程評估:客戶端組件具備執行服務所需的專有技術,但缺乏所需的資源(CPU週期,數據源等),剛好位於遠程站點。所以,客戶端將技術訣竅發送到遠程站點的服務器組件,該服務器組件又使用那裏可用的資源來執行代碼。而後將執行結果發送回客戶端。遠程評估樣式假定所提供的代碼將在受保護的環境中執行,這樣除了正在使用的資源以外,它不會影響同一服務器的其餘客戶端。
  • 按需代碼:在按需代碼樣式中,客戶端組件能夠訪問一組資源,但不能訪問如何處理它們的專有技術。它向遠程服務器發送請求,以獲取表明該技術訣竅的代碼,接收該代碼並在本地執行該代碼。
  • 移動代理:在移動代理風格中,整個計算組件與其狀態,所需代碼以及執行任務所需的一些數據一塊兒被移動到遠程站點。這能夠被認爲是遠程評估和按需編碼樣式的推導,由於移動性能夠雙向工做。

2 設計Web架構:問題和看法

2.1 萬維網應用程序要求

       伯納斯 - 李寫道,「網絡的主要目標是成爲人和機器能夠通訊的共享信息空間。」 所須要的是人們存儲和構建他們本身的信息的方式,不管是永久性的仍是短暫的,以便它自己和其餘人能夠使用,而且可以參考和構建他人存儲的信息,以便它沒有必要讓每一個人保持和維護本地副本。

       該系統的預期最終用戶位於世界各地,經過互聯網鏈接的各類大學和政府高能物理研究實驗室。他們的機器是終端,工做站,服務器和超級計算機的異構集合,須要大量的操做系統軟件和文件格式。信息範圍從我的研究筆記到組織電話列表。面臨的挑戰是創建一個系統,爲這種結構化信息提供通用的一致界面,儘量在儘量多的平臺上提供,並在新人和組織加入項目時逐步部署。

2.1.1 低入口障礙

       因爲參與信息的建立和構建是自願的,所以須要較低的准入門檻以實現充分的採用。這適用於Web體系結構的全部用戶:讀者,做者和應用程序開發人員。

       超媒體被選爲用戶界面,由於它簡單和通用:不管信息源如何,均可以使用相同的界面,超媒體關係(連接)的靈活性容許無限制的結構,直接操縱連接容許內部的複雜關係指導讀者完成申請的信息。因爲大型數據庫中的信息一般更容易經過搜索界面而不是瀏覽來訪問,所以Web還經過向服務提供用戶輸入的數據並將結果呈現爲超媒體來結合執行簡單查詢的能力。

       對於做者來講,主要要求是整個系統的部分可用性不得妨礙內容的創做。超文本創做語言必須簡單而且可以使用現有編輯工具建立。做者須要保留這種格式的我的研究筆記,不管是否直接鏈接到互聯網,所以暫時或永久地提供某些參考信息的事實不能阻止閱讀和創做。可用的信息。出於相似的緣由,必須可以在該參考的目標可用以前建立對信息的引用。因爲鼓勵做者在信息源的開發方面進行合做,所以參考文獻須要易於溝通。

       簡單性也是應用程序開發人員的目標。因爲全部協議都被定義爲文本,所以能夠使用現有網絡工具查看和交互測試通訊。儘管缺少標準,這使得早期採用協議成爲可能。

2.1.2 可擴展性

       雖然簡單性能夠部署分佈式系統的初始實現,但可擴展性使咱們可以避免因部署的限制而永遠陷入困境。即便能夠構建徹底符合其用戶要求的軟件系統,這些要求也會隨着社會隨着時間的推移而變化。一個打算像Web同樣長壽的系統必須爲變革作好準備。

2.1.3 分佈式超媒體

       超媒體的定義是信息呈現中嵌入的應用程序控制信息的存在或上面的層。分佈式超媒體容許將演示和控制信息存儲在遠程位置。就其本質而言,分佈式超媒體系統內的用戶動做須要將大量數據從存儲數據的位置傳輸到使用它的位置。所以,Web架構必須設計用於大粒度數據傳輸。

       超媒體交互的可用性對用戶感知的延遲高度敏感:選擇連接和呈現可用結果之間的時間。因爲Web的信息源分佈在全球Internet上,所以架構須要最小化網絡交互(數據傳輸協議內的往返)。

2.1.4 互聯網規模

       Web旨在成爲一個互聯網規模的分佈式超媒體系統,這意味着不只僅是地理分散。互聯網是指跨多個組織邊界互連信息網絡。信息服務的供應商必須可以應對無政府可擴展性和軟件組件的獨立部署的需求。

2.1.4.1 無狀態可擴展性

       大多數軟件系統是在隱含的假設下建立的,即整個系統處於一個實體的控制之下,或者至少參與系統內的全部實體都在朝着共同目標而不是交叉目的行事。當系統在因特網上公開運行時,不能安全地作出這樣的假設。無狀態可擴展性是指架構元素在遭受意外負載時或在給出格式錯誤或惡意構造的數據時須要繼續運行,由於它們可能與組織控制以外的元素進行通訊。該體系結構必須適合加強可見性和可伸縮性的機制。

       無狀態性可擴展性要求適用於全部架構元素。不能指望客戶端保持全部服務器的狀態。不能指望服務器跨請求保留狀態知識。超媒體數據元素不能保留「反向指針」,即引用它們的每一個數據元素的標識符,由於對資源的引用數量與對該信息感興趣的人數成比例。特別值得注意的信息也可能致使「閃電人羣」:隨着其可用性的消息傳播到全世界,訪問嘗試忽然激增。

       建築元素的安全性以及它們運行的平臺也成爲一個重要的問題。多個組織邊界意味着在任何通訊中均可能存在多個信任邊界。中間件應用程序(例如防火牆)應該可以檢查應用程序交互並防止對組織安全策略以外的人員採起行動。應用程序交互的參與者應該假定所接收的任何信息都是不可信的,或者在得到信任以前須要一些額外的身份驗證。這要求體系結構可以傳遞身份驗證數據和受權控制。

2.1.4.2 獨立部署

       多個組織邊界還意味着系統必須爲逐步和零散的變動作好準備,新舊實現共存,而不會阻止新實現利用其擴展功能。須要設計現有的架構元素,指望將添加之後的架構特徵。一樣,須要輕鬆識別較舊的實現,以即可以封裝遺留行爲,而不會對新的體系結構元素產生負面影響。整個體系結構必須設計爲以部分,迭代的方式簡化體系結構元素的部署,由於不可能以有序的方式強制部署。

2.2 問題

       在1993年底,很明顯,不只僅是研究人員會對網絡感興趣。網絡首先發生在小型研究小組中,而後傳播到校園宿舍,俱樂部和我的主頁,而後傳播到機構部門獲取校園信息。當我的開始發佈他們的我的信息集時,不管他們可能感到什麼狂熱的話題,社交網絡效應推進了今天持續的網站的指數增加。對網絡的商業興趣纔剛剛開始,但很明顯,在國際範圍內發佈的能力對企業來講是不可抗拒的。

       儘管互聯網開發者社區的成功使人高興,但他們開始擔憂網絡使用的快速增加以及早期HTTP的一些不良網絡特徵將迅速超過互聯網基礎設施的容量並致使全面崩潰。因爲Web上應用程序交互的性質不斷變化,這種狀況更加惡化。儘管初始協議是針對單個請求 - 響應對而設計的,但新站點使用愈來愈多的內嵌圖像做爲網頁內容的一部分,從而產生用於瀏覽的不一樣交互配置文件。部署的體系結構在支持可擴展性,共享緩存和中介體方面存在很大的侷限性,這使得難以針對不斷增加的問題開發臨時解決方案。與此同時,

       Internet工程任務組內的工做組成立於Web的三個主要標準:URI,HTTP和HTML。這些組的章程是定義現有架構通訊的子集,這些子集在早期Web架構中一般一致地實現,識別該架構中的問題,而後指定一組標準來解決這些問題。這給咱們帶來了一個挑戰:咱們如何爲已經普遍部署的體系結構引入一組新功能,以及咱們如何確保其引入不會對啓用Web的體系結構屬性產生負面影響甚至破壞成功?

2.3 方法

       早期的Web架構基於可靠的原則 - 關注點分離,簡單性和通用性 - 但缺少架構描述和基本原理。該設計是基於一套非正式的超文本筆,對用戶社區和Web開發者社區郵件列表存檔的討論(www-talk@info.cern.ch) 。然而,實際上,早期Web架構的惟一真實描述是在libwww(客戶端和服務器的CERN協議庫),Mosaic(NCSA瀏覽器客戶端)以及與它們互操做的各類其餘實現的實現中找到的。 。

       架構風格可用於定義Web架構背後的原則,以便將來的架構師能夠看到它們。如第1章所述,樣式是體系結構元素上的一組命名約束,它引入了體系結構所需的屬性集。所以,個人方法的第一步是肯定早期Web架構中對其所需屬性負責的約束。

       假設I:WWW體系結構背後的設計原理能夠經過一種體系結構樣式來描述,該體系結構樣式由應用於Web體系結構中的元素的約束集組成。
能夠將附加約束應用於體系結構樣式,以便擴展在實例化體系結構上引起的屬性集。個人方法的下一步是肯定互聯網規模的分佈式超媒體系統中所需的屬性,選擇誘導這些屬性的其餘架構風格,並將它們與早期的Web約束相結合,以造成現代Web的新的混合架構風格。建築。

       假設II:能夠將約束添加到WWW體系結構樣式中,以得到更好地反映現代Web體系結構所需屬性的新混合樣式。
使用新的體系結構樣式做爲指導,咱們能夠將建議的擴展和對Web體系結構的修改與樣式中的約束進行比較。衝突代表該提案違反了Web背後的一個或多個設計原則。在某些狀況下,能夠經過在使用新功能時要求使用特定指示符來消除衝突,這一般對影響響應的默承認緩存性的HTTP擴展進行。對於嚴重的衝突,例如交互風格的改變,相同的功能要麼被更有利於Web風格的設計所取代,要麼被告知提議者將功能實現爲與Web並行運行的獨立體系結構。 。

       假設III:能夠將修改Web體系結構的提議與更新的WWW體系結構樣式進行比較,並在部署以前分析衝突。
最後,經過參與構成大多數Web應用程序的基礎架構和中間件軟件的開發,部署了根據新架構風格指南編寫的修訂協議標準所定義的更新Web架構。這包括我直接參與Apache HTTP服務器項目和libwww-perl客戶端庫的軟件開發,以及經過爲W3C libwww和jigsaw項目,Netscape Navigator,Lynx和MSIE的開發人員提供建議,間接參與其餘項目。瀏覽器和許多其餘實現,做爲IETF話語的一部分。

       雖然我已將此方法描述爲單個序列,但實際上它是以非順序,迭代的方式應用的。也就是說,在過去六年中,我一直在構建模型,爲架構風格添加約束,並經過客戶端和服務器軟件的實驗擴展來測試它們對Web協議標準的影響。一樣,其餘人建議在架構中添加超出當前模型樣式範圍的功能,但不與其衝突,這致使返回並修改架構約束以更好地反映改進的架構。咱們的目標始終是保持一致且正確的模型,即我打算如何構建Web體系結構,以便它能夠用於指導定義適當行爲的協議標準。

3 REST架構風格

       REST是一種混合風格,它源自第1章中描述的幾種基於網絡的體系結構樣式,並結合了定義統一鏈接器接口的其餘約束。第1章的軟件體系結構框架用於定義REST的體系結構元素,並檢查原型體系結構的樣本過程,鏈接器和數據視圖。

3.1 派生REST

       Web體系結構背後的設計原理能夠經過體系結構樣式來描述,該體系結構樣式由應用於體系結構中的元素的約束集組成。經過檢查每一個約束在添加到演化樣式時的影響,咱們能夠識別由Web約束引發的屬性.而後能夠應用其餘約束來造成新的體系結構樣式,以更好地反映現代Web體系結構的所需屬性。本節經過介紹將其做爲架構風格派生的過程,提供REST的通常概述。後面的部分將更詳細地描述組成REST樣式的特定約束。

3.1.1 從空樣式開始

       建築設計過程有兩個共同的觀點,不管是建築物仍是軟件。第一個是設計師從零開始 - 空白的板岩,白板或繪圖板 - 並從熟悉的組件構建架構,直到知足預期系統的需求。第二個是設計師從系統需求開始,沒有約束,而後逐步識別並應用系統元素的約束,以區分設計空間,並容許影響系統行爲的力天然流動,與系統和諧相處。第一個強調創造力和無限視覺,第二個強調對系統環境的約束和理解。使用後一種方法開發了REST。

       空樣式只是一組空的約束。從體系結構的角度看,空樣式描述了一個系統其中組件之間沒有明顯的邊界這是咱們描述REST的起點。

3.1.2 客戶端-服務器

       添加到混合樣式的第一個約束是客戶端 - 服務器體系結構樣式。關注點分離是客戶端 - 服務器約束背後的原則。經過將用戶界面問題與數據存儲問題分開,咱們提升了跨多個平臺的用戶界面的可移植性,並經過簡化服務器組件來提升可伸縮性。然而,對Web而言最重要的是,分離容許組件獨立發展,從而支持多個組織域的Internet規模需求。

3.1.3 無狀態

       接下來咱們爲客戶端 - 服務器交互添加一個約束:通訊本質上必須是無狀態的。這樣每一個請求從客戶端到服務器必須包含理解請求所需的全部信息,而且不能利用服務器上任何存儲的上下文。所以,會話狀態徹底保留在客戶端上。此約束會引起可見性,可靠性和可伸縮性。

       可見性獲得改善,由於監控系統沒必要超出單個請求數據,以肯定請求的完整性。可靠性獲得改善,由於它簡化了從部分故障中恢復的任務。擴展性獲得改善,由於沒必要在請求之間存儲狀態容許服務器組件快速釋放資源,並進一步簡化實現,由於服務器沒必要跨請求管理資源使用。

       與大多數架構選擇同樣,無狀態約束反映了設計權衡。缺點是它可能經過增長在一系列請求中發送的重複數據(每一個交互開銷)來下降網絡性能,由於該數據不能在共享上下文中留在服務器上。此外,將應用程序狀態放在客戶端會下降服務器對一致應用程序行爲的控制,由於應用程序依賴於跨多個客戶端版本的語義的正確實現。

3.1.4 緩存

       爲了提升網絡效率,咱們添加了緩存約束以造成客戶端緩存無狀態服務器樣式。高速緩存約束要求將對請求的響應中的數據隱式或顯式標記爲可高速緩存或不可高速緩存。若是響應是可緩存的,則客戶端緩存有權重用該響應數據以用於之後的等效請求。

       添加緩存約束的優點在於,它們有可能經過減小一系列交互的平均延遲來部分或徹底消除某些交互,從而提升效率,可伸縮性和用戶感知性能。然而,權衡的是,若是高速緩存中的陳舊數據與請求被直接發送到服務器時得到的數據顯著不一樣,則高速緩存會下降可靠性。

       早期的Web架構是由客戶端緩存無狀態服務器約束集定義的。也就是說,1994年以前爲Web架構提供的設計原理側重於經過Internet交換靜態文檔的無狀態客戶端 - 服務器交互。用於通訊交互的協議對非共享緩存具備基本支持,但並未將接口限制爲全部資源的一致語義集。相反,Web依賴於使用通用客戶端 - 服務器實現庫(CERN libwww)來維護Web應用程序之間的一致性。

       目前,Web開發已經超出了早期的設計。除靜態文檔外,請求還能夠識別動態生成響應的服務,例如圖像映射[Kevin Hughes]和服務器端腳本[Rob McCool]。代理和共享緩存 形式的中間組件也已開始工做,但須要對協議進行擴展才能使它們可靠地進行通訊。如下部分描述了添加到Web體系結構樣式的約束,以指導構成現代Web體系結構的擴展。

3.1.5 統一接口

       將REST架構樣式與其餘基於網絡的樣式區分開來的核心功能是強調組件之間的統一接口。經過將通用性的軟件工程原理應用於組件接口,簡化了整個系統架構,提升了交互的可見性。實現與它們提供的服務分離,這鼓勵了獨立的可進化性。然而,權衡的是,統一的接口會下降效率,由於信息是以標準化的形式傳輸的,而不是特定於應用程序需求的形式。REST接口旨在高效地進行大粒度超媒體數據傳輸,並針對Web的常見狀況進行優化,然而,它又會帶來界面不適合其餘形式的架構交互的負面效應。

       爲了得到統一的接口,須要多個架構約束來指導組件的行爲。REST由四個接口約束定義:資源識別、 經過陳述來處理資源、 自我描述性的信息和超媒體做爲應用程序狀態的引擎。

3.1.6 分層系統

       爲了進一步改善Internet規模要求的行爲,咱們添加了分層系統約束。分層系統樣式容許經過約束組件行爲來使架構由分層組成,使得每一個組件不能「看到」超出與它們交互的直接層。經過將系統知識限制在單一層,咱們限制了整個系統的複雜性並促進了基板的獨立性。層可用於封裝舊服務並保護舊服務的新服務,經過將不經常使用的功能移動到共享中介來簡化組件。經過在多個網絡和處理器之間實現服務的負載平衡,中介還可用於提升系統可擴展性。

       分層系統的主要缺點是它們增長了數據處理的開銷和延遲,下降了用戶感知的性能。對於支持緩存約束的基於網絡的系統,這能夠經過中間人的共享緩存的好處來抵消。將共享緩存放置在組織域的邊界能夠帶來顯着的性能優點。這些層還容許對跨越組織邊界的數據實施安全策略,這是防火牆所要求的。

       分層系統和均勻界面約束的組合引發相似於均勻管道和過濾器類型的建築特性。雖然REST交互是雙向的,可是超媒體交互的大粒度數據流能夠像數據流網絡同樣被處理,其中過濾器組件選擇性地應用於數據流,以便在內容經過時轉換內容。在REST中,中間組件能夠主動轉換消息內容,由於消息是自描述的,而且它們的語義對於中介是可見的。

3.1.7 按需代碼

       REST的約束集的最終添加來自第1.3.3節的移動代碼樣式。REST容許經過以applet或腳本的形式下載和執行代碼來擴展客戶端功能。這經過減小預先實現所需的功能數量來簡化客戶端。容許在部署後下載功能能夠提升系統的可擴展性。可是,它還會下降可見性,所以只是REST中的可選約束。

       可選約束的概念可能看起來像矛盾。可是,它在包含多個組織邊界的系統的體系結構設計中確實有用。這意味着當已知對於整個系統的某些領域有效時,該體系結構僅得到可選約束的益處(而且具備缺點)。例如,若是已知組織內的全部客戶端軟件都支持Java applet,而後,能夠構建該組織內的服務,以便經過可下載的Java類得到加強功能的好處。可是,同時,組織的防火牆可能會阻止Java小程序從外部源傳輸,所以對於Web的其他部分,它看起來好像這些客戶端不支持按需代碼。可選約束容許咱們設計一種在通常狀況下支持所需行爲的體系結構,但要了解它可能在某些上下文中被禁用。

3.2 REST架構元素

       Representational State Transfer(REST)樣式是分佈式超媒體系統中的架構元素的抽象。REST忽略了組件實現和協議語法的細節,以便專一於組件的角色,與其餘組件交互的約束以及對重要數據元素的解釋。它包含對組件,鏈接器和數據的基本約束,這些約束定義了Web體系結構的基礎,所以也就是其做爲基於網絡的應用程序的行爲的本質。

3.2.1 數據元素

數據元素 現代web示例
資源 超文本引用的預期概念目標
資源標識符 URL,URN
表示 HTML文檔,JPEG圖像
表示元數據 媒體類型,最後修改時間
資源元數據 源連接,交替,變化
控制數據 if-modified-since,cache-control

       REST經過關注數據類型與元數據的共享理解,提供了全部三個選項的混合,但限制了標準化界面的顯示範圍。REST組件經過以匹配一組演進的標準數據類型之一的格式傳送資源的表示來進行通訊,所述標準數據類型基於接收者的能力或指望以及資源的性質而動態地選擇。表示是否與原始源具備相同的格式,或者是否源自源,仍然隱藏在接口後面。經過發送由封裝渲染引擎的標準數據格式中的指令組成的表示來近似移動對象樣式的好處。所以,REST能夠在沒有服務器可伸縮性問題的狀況下實現客戶端 - 服務器風格的關注分離,容許經過通用接口隱藏信息以實現服務的封裝和演進,並經過可下載的功能引擎提供各類功能。

3.2.1.1 資源和資源標識符

       REST中信息的關鍵抽象是一種資源。能夠命名的任何信息均可以是資源:文檔或圖像,臨時服務(例如「洛杉磯的今每天氣」),其餘資源的集合,非虛擬對象(例如人)等等。換句話說,任何多是做者超文本引用目標的概念都必須符合資源的定義。資源是到一組實體的概念映射,而不是與任何特定時間點的映射相對應的實體。

       更確切地說,資源R是時間上變化的隸屬函數M R(t),其對於時間t映射到一組實體或等價的值。集合中的值能夠是資源表示和/或資源標識符。資源能夠映射到空集,容許在任何實現該概念以前對概念進行引用 - 這一律唸對於Web以前的大多數超文本系統來講是陌生的[ 61]]。某些資源在某種意義上是靜態的,當它們在建立後的任什麼時候間進行檢查時,它們老是對應於相同的值集。其餘人的價值隨時間變化很大。對於資源而言,惟一須要靜態的是映射的語義,由於語義是區分一個資源與另外一個資源的區別。

       例如,學術論文的「做者'首選版本」是其值隨時間變化的映射,而映射到「在會議X的會議論文中發表的論文」是靜態的。這是兩個不一樣的資源,即便它們在某個時間點都映射到相同的值。區分是必要的,以即可以獨立地識別和引用這兩種資源。軟件工程中的相似示例是在引用「最新版本」,「版本號1.2.7」或「橙色版本附帶的修訂版」時單獨標識版本控制的源代碼文件。

       這種資源的抽象定義實現了Web體系結構的關鍵功能。首先,它經過包含許多信息來源提供了通常性,而沒有按類型或實施人爲地區分它們。其次,它容許將引用後期綁定到表示,從而容許基於請求的特徵進行內容協商。最後,它容許做者引用該概念而不是該概念的某些單一表示,從而無需在表示發生變化時更改全部現有連接(假設做者使用了正確的標識符)。

       REST使用資源標識符來標識組件之間交互中涉及的特定資源。不管如何定義成員函數或處理請求的軟件類型,REST鏈接器都提供用於訪問和操做資源值集的通用接口。分配資源標識符使得能夠引用資源的命名機構負責維持映射隨時間的語義有效性(即,確保成員函數不改變)。

       傳統的超文本系統一般在封閉或本地環境中運行,使用每次信息更改時都會發生變化的惟一節點或文檔標識符,依靠連接服務器來維護與內容分開的引用。因爲集中式連接服務器是對Web的巨大規模和多組織域要求的詛咒,所以REST依賴於做者選擇最符合所識別概念性質的資源標識符。固然,標識符的質量一般與保留其有效性所花費的金額成比例,這致使連接斷開,由於短暫(或支持不良)的信息隨着時間的推移而移動或消失。

3.2.1.2 表示

       REST組件經過使用表示來捕獲資源的當前或預期狀態並在組件之間傳輸該表示,從而對資源執行操做。表示是字節序列,加上用於描述這些字節的表示元數據。其餘經常使用但不太精確的表示名稱包括:文檔,文件和HTTP消息實體,實例或變體。

       表示由數據,描述數據的元數據以及有時描述元數據的元數據(一般用於驗證消息完整性)組成。元數據採用名稱 - 值對的形式,其中名稱對應於定義值的結構和語義的標準。響應消息能夠包括表示元數據和資源元數據:關於不是特定於所提供的表示的資源的信息。

       控制數據定義組件之間消息的目的,例如所請求的操做或響應的含義。它還用於參數化請求並覆蓋某些鏈接元素的默認行爲。例如,能夠經過請求或響應消息中包括的控制數據來修改高速緩存行爲。

       根據消息控制數據,給定表示能夠指示所請求資源的當前狀態,所請求資源的指望狀態,或某些其餘資源的值,例如客戶端查詢形式內的輸入數據的表示,或者表示響應的某些錯誤條件。例如,資源的遠程創做要求做者向服務器發送表示,從而爲該資源創建可由後來的請求檢索的值。若是給定時間的資源的值集由多個表示組成,則能夠使用內容協商來選擇包含在給定消息中的最佳表示。

       表示的數據格式稱爲媒體類型。表示能夠包括在消息中並由接收者根據消息的控制數據和媒體類型的性質進行處理。一些媒體類型旨在用於自動處理,一些媒體類型旨在被呈現以供用戶查看,而且一些媒體類型可以用於二者。複合媒體類型可用於在單個消息中包含多個表示。

       媒體類型的設計能夠直接影響分佈式超媒體系統的用戶感知性能。在收件人開始呈現表示以前必須接收的任何數據都會增長交互的延遲。一種數據格式,能夠預先放置最重要的渲染信息,這樣能夠在接收其他信息時逐步渲染初始信息,從而產生比之前必須徹底接收的數據格式更好的用戶感知性能渲染能夠開始。

       例如,即便網絡性能相同,能夠在接收大量HTML文檔時逐步呈現大型HTML文檔的Web瀏覽器提供的用戶感知性能明顯優於在呈現以前等待整個文檔徹底接收的文檔。請注意,表示的呈現能力也可能受到內容選擇的影響。若是必須在渲染動態大小的表和嵌入對象以前肯定它們的尺寸,則它們在超媒體頁面的查看區域內的出現將增長其延遲。

3.2.2 鏈接器

鏈接器 現代web示例
客戶 libwww,libwww-perl
服務器 libwww,Apache API,NSAPI
高速緩存 瀏覽器緩存,Akamai緩存網絡
分解器 綁定(DNS查找庫)
隧道 HTTP CONNECT後的SOCKS,SSL

       REST使用上表中彙總的各類鏈接器類型來封裝訪問資源和傳輸資源表示的活動。鏈接器爲組件通訊提供了一個抽象接口,經過提供關注點的清晰分離和隱藏資源和通訊機制的底層實現來加強簡單性。接口的通用性還具備可替代性:若是用戶只能經過抽象接口訪問系統,則能夠在不影響用戶的狀況下替換實現。因爲鏈接器管理組件的網絡通訊,所以能夠跨多個交互共享信息,以提升效率和響應性。

       全部REST交互都是無狀態的。也就是說,每一個請求都包含鏈接器理解請求所需的全部信息,與以前可能存在的任何請求無關。此限制實現了四個功能:1)它消除了鏈接器在請求之間保留應用程序狀態的任何須要,從而減小了物理資源的消耗並提升了可伸縮性; 2)它容許並行處理交互,而不須要處理機制理解交互語義; 3)它容許中介單獨查看和理解請求,這在動態從新安排服務時多是必要的; 4)它強制全部可能影響緩存響應的可重用性的信息出如今每一個請求中。

       鏈接器接口相似於過程調用,但在參數和結果的傳遞方面存在重要差別。參數包括請求控制數據,指示請求目標的資源標識符和可選表示。out參數包括響應控制數據,可選資源元數據和可選表示。從抽象的角度來看,調用是同步的,但in-out和out-parameters均可以做爲數據流傳遞。換句話說,能夠在徹底知道參數的值以前調用處理,從而避免批量處理大數據傳輸的等待時間。

       主鏈接器類型是客戶端和服務器。二者之間的本質區別在於客戶端經過發出請求來啓動通訊,而服務器偵聽鏈接並響應請求以提供對其服務的訪問。組件能夠包括客戶端和服務器鏈接器。

       第三種鏈接器類型(緩存鏈接器)能夠位於客戶端或服務器鏈接器的接口上,以便保存對當前交互的可緩存響應,以即可以將它們重用於之後請求的交互。客戶端能夠使用高速緩存來避免重複網絡通訊,或者服務器能夠使用高速緩存來避免重複生成響應的過程,兩種狀況都用於減小交互等待時間。緩存一般在使用它的鏈接器的地址空間內實現。

       某些緩存鏈接器是共享的,這意味着其緩存的響應可用於回答除最初得到響應的客戶端以外的客戶端。共享緩存能夠有效地減小「閃存擁擠」對流行服務器負載的影響,特別是當分層安排緩存以覆蓋大型用戶組時,例如公司內部網中的用戶,Internet服務的客戶提供者或共享國家網絡骨幹的大學。可是,若是緩存的響應與新請求所得到的響應不匹配,則共享緩存也會致使錯誤。REST嘗試平衡緩存行爲透明度的願望與有效使用網絡的願望,而不是假設始終須要絕對透明度。

       緩存可以肯定響應的可緩存性,由於該接口是通用的,而不是特定於每一個資源。默認狀況下,對檢索請求的響應是可緩存的,對其餘請求的響應是不可緩存的。若是某種形式的用戶身份驗證是請求的一部分,或者響應指示不該該共享,則響應只能由非共享緩存緩存。組件能夠經過包含控制數據來覆蓋這些默認值,該控制數據僅在有限時間內將交互標記爲可緩存,不可緩存或可緩存。

       解析器將部分或完整資源標識符轉換爲創建組件間鏈接所需的網絡地址信息。例如,大多數URI包括DNS主機名做爲用於標識資源的命名權限的機制。爲了發起請求,Web瀏覽器將從URI中提取主機名,並使用DNS解析器獲取該權限的Internet協議地址。另外一個示例是一些識別方案(例如,URN須要中間設備將永久標識符轉換爲更臨時的地址以便訪問所識別的資源。使用一個或多箇中間解析器能夠經過間接提升資源引用的壽命,但這樣作會增長請求延遲。

       鏈接器類型的最終形式是隧道,它簡單地中繼經過鏈接邊界的通訊,例如防火牆或低級網絡網關。將其建模爲REST的一部分而且不做爲網絡基礎結構的一部分進行抽象的惟一緣由是某些REST組件能夠動態地從活動組件行爲切換到隧道的行爲。主要示例是HTTP代理,它響應CONNECT方法請求切換到隧道,從而容許其客戶端使用不容許代理的不一樣協議(如TLS)直接與遠程服務器通訊。當兩端終止通訊時,隧道消失。

3.2.3 組件

組件 現代web示例
原始服務器 Apache httpd,Microsoft IIS
網關 Squid,CGI,反向代理
代理 CERN代理,Netscape代理,Gauntlet
用戶代理 Netscape Navigator,Lynx,MOMspider

       用戶代理使用客戶端鏈接器來發起請求,併成爲響應的最終接收者。最多見的示例是Web瀏覽器,它提供對信息服務的訪問並根據應用程序需求呈現服務響應。

       源服務器使用服務器鏈接器來管理所請求資源的命名空間。它是表示其資源的權威來源,而且必須是任何打算修改其資源價值的請求的最終接收者。每一個源服務器都將其服務的通用接口做爲資源層次結構提供。資源實現細節隱藏在界面後面。

       中介組件既做爲客戶又做爲服務器,以便轉發可能的翻譯,請求和響應。代理組件是客戶端選擇的中介,用於提供其餘服務的接口封裝,數據轉換,性能加強或安全保護。網關(也稱爲反向代理)組件是由網絡或源服務器強加的中介,以提供其餘服務的接口封裝,用於數據轉換,性能加強或安全實施。請注意,代理和網關之間的區別在於客戶端肯定什麼時候使用代理。

3.3 REST架構視圖

       如今咱們已經單獨瞭解了REST架構元素,咱們能夠使用架構視圖來描述元素如何協同工做以造成架構。三種類型的視圖 - 進程,鏈接器和數據 - 對於闡明REST的設計原則很是有用。

3.3.1 流程視圖

       REST的客戶端 - 服務器關注點分離簡化了組件實現,下降了鏈接器語義的複雜性,提升了性能調優的效率,並提升了純服務器組件的可伸縮性。分層系統約束容許在通訊中的各個點處引入中介 - 代理,網關和防火牆 - 而不改變組件之間的接口,從而容許它們經過大規模共享緩存來協助通訊轉換或提升性能。REST經過將消息約束爲自描述來實現中間處理:交互在請求之間是無狀態的,標準方法和媒體類型用於指示語義和交換信息,而且響應明確指示可緩存性。

       因爲組件是動態鏈接的,所以它們對特定應用程序操做的排列和功能具備相似於管道和過濾器樣式的特徵。雖然REST組件經過雙向流進行通訊,但每一個方向的處理是獨立的,所以易受流傳感器(過濾器)的影響。通用鏈接器接口容許根據每一個請求或響應的屬性將組件放置在流上。

       能夠使用中間體和多個分佈式源服務器的複雜層次結構來實現服務。REST的無狀態特性容許每一個交互獨立於其餘交互,無需瞭解整個組件拓撲,對於Internet規模的體系結構來講是不可能完成的任務,而且容許組件充當目的地或中介,動態肯定按每一個請求的目標。鏈接器只須要在通訊範圍內瞭解彼此的存在,但出於性能緣由,它們可能會緩存其餘組件的存在和功能。

3.3.2 鏈接器視圖

       架構的鏈接器視圖集中於組件之間的通訊機制。對於基於REST的體系結構,咱們對定義通用資源接口的約束特別感興趣。

       客戶端鏈接器檢查資源標識符,以便爲每一個請求選擇適當的通訊機制。例如,客戶端能夠被配置爲當標識符指示它是本地資源時鏈接到特定代理組件,可能一個充當註釋過濾器。一樣,客戶端能夠配置爲拒絕對某些標識符子集的請求。

       REST不限制與特定協議的通訊,但它確實限制了組件之間的接口,所以限制了組件之間可能產生的交互和實現假設的範圍。例如,Web的主要傳輸協議是HTTP,但該體系結構還包括對源自預先存在的網絡服務器的資源的無縫訪問,包括FTP ,Gopher 和WAIS 。與這些服務的交互僅限於REST鏈接器的語義。這種約束犧牲了其餘體系結構的一些優勢,例如像WAIS這樣的相關性反饋協議的狀態交互,以便保留鏈接器語義的單個通用接口的優勢。做爲回報,通用接口使得經過單個代理訪問多種服務成爲可能。若是應用程序須要另外一個體繫結構的附加功能,它能夠做爲一個並行運行的獨立系統實現和調用這些功能,相似於Web體系結構與「telnet」和「mailto」資源的接口。

3.3.3 數據視圖

       體系結構的數據視圖揭示了信息流經組件時的應用程序狀態。因爲REST專門針對分佈式信息系統,所以它將應用程序視爲信息和控制備選方案的內聚結構,用戶可經過該結構執行所需任務。例如,在在線詞典中查找單詞是一個應用程序,如在虛擬博物館中巡視,或查看一組課堂筆記以進行考試。每一個應用程序都定義了底層系統的目標,能夠衡量系統的性能。

       組件交互以動態大小的消息的形式發生。小型或中型消息用於控制語義,但大部分應用程序工做是經過包含完整資源表示的大粒度消息完成的。最多見的請求語義形式是檢索資源的表示(例如,HTTP中的「GET」方法),其一般能夠被緩存以供之後重用。

       REST將全部控制狀態集中到響應交互所接收的表示中。目標是經過消除服務器的任何須要來提升服務器可擴展性,以保持對當前請求以外的客戶端狀態的瞭解。所以,應用程序的狀態由其掛起的請求,鏈接組件的拓撲(其中一些多是過濾緩衝的數據),這些鏈接器上的活動請求,響應這些請求的表示的數據流以及這些請求的處理來定義。用戶代理收到的表示。

       只要沒有未完成的請求,應用程序就會達到穩定狀態; 即,它沒有待處理的請求,而且對其當前請求集的全部響應已被徹底接收或接收到可被視爲表示數據流的點。對於瀏覽器應用程序,此狀態對應於「網頁」,包括主要表示和輔助表示,例如內嵌圖像,嵌入式小程序和樣式表。應用穩態的重要性在於它們對用戶感知性能和網絡請求流量突發性的影響。

       瀏覽器應用程序的用戶感知性能由穩定狀態之間的延遲肯定:在一個網頁上選擇超媒體連接與爲下一個網頁呈現可用信息之間的時間段。所以,瀏覽器性能的優化集中在減小通訊延遲。

       因爲基於REST的體系結構主要經過資源表示的傳遞進行通訊,所以延遲可能受到通訊協議的設計和表示數據格式的設計的影響。在接收響應數據時遞增地呈現響應數據的能力由媒體類型的設計和每一個表示內的佈局信息(內嵌對象的視覺尺寸)的可用性肯定。

       一個有趣的觀察是,最有效的網絡請求是不使用網絡的請求。換句話說,重用緩存響應的能力能夠顯着提升應用程序性能。儘管因爲查找開銷而使用高速緩存會爲每一個單獨的請求增長一些延遲,但即便一小部分請求致使可用的高速緩存命中,也會顯着下降平均請求延遲。

       應用程序的下一個控制狀態駐留在第一個請求資源的表示中,所以得到該第一個表示是優先級。所以,經過「先響應並稍後思考」的協議來改進REST交互。換句話說,每一個用戶操做須要屢次交互的協議,以便在發送內容響應以前執行諸如協商功能能力之類的操做,將比發送最有可能首先優先的協議慢,而後提供若是第一個響應不使人滿意,客戶端要檢索的備選列表。

       應用程序狀態由用戶代理控制和存儲,而且能夠由來自多個服務器的表示組成。除了使服務器從存儲狀態的可伸縮性問題中解放出來以外,這容許用戶直接操縱狀態(例如,Web瀏覽器的歷史),預期對該狀態的改變(例如,連接映射和表示的預取)以及跳轉。從一個應用程序到另外一個應用程序(例如,書籤和URI條目對話框)。

       所以,模型應用程序是經過檢查並從當前表示集合中的備選狀態轉換中進行選擇而從一個狀態移動到下一個狀態的引擎。絕不奇怪,這與超媒體瀏覽器的用戶界面徹底匹配。可是,該樣式並不假設全部應用程序都是瀏覽器。實際上,通用鏈接器接口會從服務器隱藏應用程序詳細信息,所以用戶代理一樣能夠是爲索引服務執行信息檢索的自動化機器人,尋找符合特定條件的數據的我的代理或維護蜘蛛忙着巡邏破損的參考文獻或修改過的內容。

4 經驗和評估

       自1994年以來,REST架構風格已被用於指導現代Web架構的設計和開發。本章介紹了在建立超文本傳輸協議(HTTP)和統一資源標識符(URI)的Internet標準時應用REST所得到的經驗和教訓,這兩個規範定義了Web上全部組件交互使用的通用接口,以及以libwww-perl客戶端庫,Apache HTTP Server Project和協議標準的其餘實現形式部署這些技術。

4.1 標準化web

       開發REST的動機是爲Web應該如何工做建立一個架構模型,以便它能夠做爲Web協議標準的指導框架。REST已應用於描述所需的Web體系結構,幫助識別現有問題,比較替代解決方案,並確保協議擴展不會違反使Web成功的核心約束。這項工做是做爲Internet工程任務組(IETF)和萬維網聯盟(W3C)爲Web定義架構標準的工做的一部分完成的:HTTP,URI和HTML。

       Roy Thomas Fielding參與Web標準流程始於1993年底,同時開發了libwww-perl協議庫,做爲MOMspider的客戶端鏈接器接口。當時,Web架構是由一套非正式的超文本筆記,草擬超文本規範,表明網絡的建議功能(其中一些已經實施),以及公共www-talk郵件列表的存檔,用於全球WWW項目參與者之間的非正式討論。與Web實現相比,每一個規範都顯着過期,主要是因爲在引入Mosaic圖形瀏覽器[NCSA]以後Web的快速發展。HTTP中添加了幾個實驗性擴展以容許代理,但在大多數狀況下,協議假定用戶代理與HTTP源服務器或遺留系統的網關之間存在直接鏈接。在緩存,代理或蜘蛛的體系結構中沒有意識到,即便實現很容易得到而且沒法正常運行。

       與此同時,行業內的壓力愈來愈大,要求對Web接口協議的某些版本或版本進行標準化。W3C由Berners-Lee 組成,做爲Web架構的智庫,提供編寫Web標準和參考實現所需的創做資源,但標準化自己由Internet工程任務組管及其關於URI,HTTP和HTML的工做組。

       REST的初版是在1994年10月到1995年8月之間開發的,主要是做爲一種在咱們編寫HTTP / 1.0規範和初始HTTP / 1.1提案時傳達Web概念的方法。它在接下來的五年中獲得了迭代性的改進,並應用於Web協議標準的各類修訂和擴展。REST最初被稱爲「HTTP對象模型」,但該名稱一般會致使將其誤解爲HTTP服務器的實現模型。名稱「Representational State Transfer」旨在喚起設計良好的Web應用程序行爲的圖像:網頁網絡(虛擬狀態機),用戶經過選擇連接(狀態轉換)在應用程序中前進,

       REST並不是旨在捕獲Web協議標準的全部可能用途。HTTP和URI的應用程序與分佈式超媒體系統的應用程序模型不匹配。然而,重要的一點是REST確實捕獲了分佈式超媒體系統的全部這些方面,這些方面被認爲是Web的行爲和性能要求的核心,所以優化模型中的行爲將致使部署的Web中的最佳行爲建築。換句話說,REST針對常見狀況進行了優化,以便適用於Web體系結構的約束也將針對常見狀況進行優化。

4.2 REST應用於URI

       統一資源標識符(URI)既是Web架構中最簡單的元素,也是最重要的元素。URI已被許多名稱所知:WWW地址,通用文檔標識符,通用資源標識符,最後是統一資源定位符(URL)和名稱(URN的組合。除了它的名字以外,URI語法自1992年以來一直保持相對不變。可是,Web地址的規範也定義了咱們所說的資源的範圍和語義,資源自早期的Web架構以來已經發生了變化。REST用於定義URI標準的術語資源,以及經過其表示操做資源的通用接口的總體語義。

4.2.1 資源的從新定義

       早期的Web架構將URI定義爲文檔標識符。指示做者根據文檔在網絡上的位置定義標識符。而後能夠使用Web協議來檢索該文檔。然而,因爲許多緣由,這必定義被證實是不使人滿意的。首先,它代表做者正在識別傳輸的內容,這意味着只要內容發生變化,標識符就會發生變化。其次,存在許多與服務而不是文檔相對應的地址 - 做者可能打算將讀者引導到該服務,而不是經過先前訪問該服務的任何特定結果。最後,在某些時間段存在與文檔不對應的地址,

       REST中資源的定義基於一個簡單的前提:標識符應儘量不常常更改。由於Web使用嵌入式標識符而不是連接服務器,因此做者須要一個與超媒體引用所關注的語義緊密匹配的標識符,容許引用保持靜態,即便訪問該引用的結果可能隨時間而變化。REST經過將資源定義爲做者想要識別的語義來實現這一點,而不是在建立引用時對應於那些語義的值。而後將其留給做者以確保爲引用選擇的標識符確實標識了預期的語義。

4.2.2 操縱陰影

       定義資源使得URI標識概念而不是文檔會給咱們留下另外一個問題:用戶如何訪問,操做或轉移概念,以便在選擇超文本連接時能夠得到有用的東西?REST經過定義被操縱爲被識別資源的表示的事物而不是資源自己來回答該問題。源服務器維護從資源標識符到對應於每一個資源的表示集的映射。所以,經過經過資源標識符定義的通用接口傳送表示來操縱資源。

       REST對資源的定義源於Web的核心要求:跨多個信任域獨立建立互連超文本。強制接口定義與接口要求相匹配會致使協議看起來模糊,但這只是由於被操做的接口只是接口而不是實現。協議特定於應用程序操做的意圖,但接口背後的機制必須決定該意圖如何影響資源映射到表示的底層實現。

       信息隱藏是激發REST統一接口的關鍵軟件工程原則之一。因爲客戶端僅限於表示的操做而不是直接訪問資源的實現,所以能夠以命名機構所需的任何形式構造實現,而不會影響可能使用其表示的客戶端。另外,若是在訪問資源時存在多個資源表示,則能夠使用內容選擇算法來動態地選擇最適合該客戶端的能力的表示。固然,缺點是遠程創做資源並不像文件的遠程創做那樣簡單。

4.2.3 遠程創做

       經過Web的統一接口進行遠程創做的挑戰是因爲客戶端能夠檢索的表示與可能在服務器上用於存儲,生成或檢索該表示的內容的機制之間的分離。單個服務器能夠將其命名空間的某些部分映射到文件系統,而文件系統又映射到能夠映射到磁盤位置的inode的等效物,可是那些底層機制提供了將資源與一組表示相關聯的方法。而不是識別資源自己。許多不一樣的資源能夠映射到相同的表示,而其餘資源可能根本沒有映射。

       爲了創做現有資源,做者必須首先獲取特定的源資源URI:綁定到目標資源的處理程序底層表示的URI集。資源並不老是映射到單個文件,可是全部非靜態資源都是從其餘一些資源派生的,經過遵循派生樹,做者最終能夠找到全部必須編輯的源資源,以便修改資源的表示。這些相同的原則適用於任何形式的派生表示,不管是來自內容協商,腳本,servlet,託管配置,版本控制等。

       資源不是存儲對象。資源不是服務器用於處理存儲對象的機制。資源是概念映射 - 服務器接收標識符(標識映射)並將其應用於其當前映射實現(一般是特定於集合的深層樹遍歷和/或散列表的組合)以查找當前負責的處理程序而後,實現和處理程序實現根據請求內容選擇適當的操做+響應。全部這些特定於實現的問題都隱藏在Web界面以後; 它們的性質不能由只能經過Web界面訪問的客戶端承擔。

       例如,考慮當網站在用戶羣中增加並決定用基於XOS平臺的舊的Brand X服務器替換在FreeBSD上運行的新Apache服務器時會發生什麼。磁盤存儲硬件已更換。操做系統已被替換。HTTP服務器已被替換。甚至能夠替換爲全部內容生成響應的方法。可是,不須要更改的是Web界面:若是設計正確,新服務器上的命名空間能夠反映舊服務器上的命名空間,這意味着從客戶端的角度來看,它只知道資源而不知道它們是如何實現的除了網站改進的穩健性以外,沒有任何改變。

4.2.4 將語義綁定到URI

       如上所述,資源能夠具備許多標識符。換句話說,當用於訪問服務器時,可能存在兩個或更多個具備等效語義的不一樣URI。也可能有兩個URI致使在訪問服務器時使用相同的機制,但這些URI標識兩個不一樣的資源,由於它們並不意味着相同的事情。

       語義是分配資源標識符並用表示填充這些資源的行爲的副產品。在任什麼時候候,服務器或客戶端軟件都不須要知道或理解URI的含義 - 它們只是做爲一個管道,資源的建立者(人類命名機構)能夠經過該管道將表示與由表示的語義相關聯。 URI。換句話說,服務器上沒有資源; 只是經過資源定義的抽象接口提供答案的機制。這可能看起來很奇怪,但這是使Web在許多不一樣實現中工做的本質。

       每一個工程師的本質是根據將用於組成成品的組件的特徵來定義事物。網絡不是這樣的。Web體系結構包括組件之間通訊模型的約束,基於應用程序操做期間每一個組件的角色。這能夠防止組件假設超出資源抽象的任何內容,從而隱藏抽象接口任一側的實際機制。

4.2.5 URI中的REST不匹配

       與大多數現實世界系統同樣,並不是所部署的Web體系結構的全部組件都遵循其體系結構設計中存在的每一個約束。REST既被用做定義架構改進的手段,也用於識別架構不匹配。當因爲無知或疏忽而部署了違反架構約束的軟件實現時,會發生不匹配。雖然一般沒法避免不匹配,但能夠在它們變得標準化以前識別它們。

       雖然URI設計符合REST的標識符架構概念,但僅憑語法不足以迫使命名機構根據資源模型定義本身的URI。濫用的一種形式是包括標識超媒體響應表示所引用的全部URI中的當前用戶的信息。此類嵌入式用戶ID可用於維護服務器上的會話狀態,經過記錄其操做來跟蹤用戶行爲,或跨多個操做(例如,Hyper-G的網關[ 84 ])攜帶用戶首選項。可是,經過違反REST的約束,這些系統還會致使共享緩存變得無效,下降服務器可伸縮性,並在用戶與其餘人共享這些引用時致使不良影響。

       當軟件試圖將Web視爲分佈式文件系統時,會發生與REST資源接口的另外一個衝突。因爲文件系統公開其信息的實現,所以存在將該信息「鏡像」到多個站點的工具,做爲負載平衡和將內容從新分佈到用戶附近的手段。可是,他們只能這樣作,由於文件具備一組固定的語義(一個命名的字節序列),能夠輕鬆複製。相反,嘗試將Web服務器的內容鏡像爲文件將失敗,由於資源接口並不老是與文件系統的語義匹配,而且由於數據和元數據都包含在表示的語義中,而且對於表示的語義很重要。Web服務器內容能夠在遠程站點複製,

4.3 REST應用於HTTP

       超文本傳輸協議(HTTP)在Web體系結構中具備特殊的做用,它既是Web組件之間通訊的主要應用程序級協議,也是專門爲資源表示傳輸而設計的惟一協議。與URI不一樣,爲了支持現代Web架構,須要進行大量更改。HTTP實現的開發人員在採用提議的加強功能時一直保守,所以擴展須要在部署以前進行驗證並進行標準審查。REST用於識別現有HTTP實現的問題,將該協議的可互操做子集指定爲HTTP / 1.0 [ 19 ],分析HTTP / 1.1的建議擴展[ 42]],並提供部署HTTP / 1.1的激勵理由。

       由REST識別的HTTP中的關鍵問題區域包括規劃新協議版本的部署,將消息解析與HTTP語義和底層傳輸層(TCP)分離,區分權威和非權威響應,細粒度控制緩存,以及沒法自我描述的協議的各個方面。REST還被用於模擬基於HTTP的Web應用程序的性能,並預測這些擴展對持久鏈接和內容協商的影響。最後,REST已被用於將標準化HTTP擴展的範圍限制爲適合體系結構模型的範圍,而不是容許濫用HTTP的應用程序同等地影響標準。

4.3.1 可擴展性

       REST的主要目標之一是支持在已部署的體系結構中逐步和分散的更改部署。經過引入版本控制要求和規則來修改HTTP以支持該目標,以擴展每一個協議的語法元素。

4.3.1.1 協議版本控制

       HTTP是一系列協議,由主要版本號和次要版本號區分,它們共享名稱主要是由於它們對應於直接與基於「http」URL命名空間的服務通訊時所指望的協議。鏈接器必須遵照每條消息中包含的HTTP版本協議元素的約束。

       消息的HTTP版本表示發送方的協議功能以及正在發送的消息的總兼容性(主要版本號)。這容許客戶端在發出正常的HTTP / 1.1請求時使用簡化的(HTTP / 1.0)特徵子集,同時向接收者指示它可以支持完整的HTTP / 1.1通訊。換句話說,它在HTTP規模上提供了一種暫定形式的協議協商。儘管某些客戶端或服務器是鏈的一部分,但請求/響應鏈上的每一個鏈接均可以在其最佳協議級別運行。

       協議的目的是服務器應始終使用它在客戶端請求消息的相同主要版本中理解的協議的最高次要版本進行響應。限制是服務器不能使用更高級別協議的那些可選功能,這些功能被禁止發送到這樣的舊版客戶端。協議沒有必需的功能,不能與該主要版本中的全部其餘次要版本一塊兒使用,由於這將是不兼容的更改,所以須要更改主要版本。能夠依賴於次要版本號更改的HTTP的惟一功能是由通訊中的直接鄰居解釋的那些功能,由於HTTP不要求中間組件的整個請求/響應鏈說出相同的版本。

       存在這些規則以幫助部署多個協議修訂並防止HTTP架構師忘記協議的部署是其設計的重要方面。他們經過簡化協議的兼容更改和不兼容的更改來實現這一點。兼容的更改易於部署,而且能夠在協議流內實現差別的通訊。不兼容的更改難以部署,由於它們須要在協議流開始以前肯定接受協議。

4.3.1.2 可擴展協議元素

       HTTP包括許多單獨的命名空間,每一個命名空間都有不一樣的約束,但全部這些命名空間都共享無限制可擴展的要求。一些命名空間由不一樣的Internet標準管理,並由多個協議共享(例如,URI方案[ 21 ],媒體類型[ 48 ],MIME頭字段名[ 47 ],字符集值,語言標籤),而其餘名稱由HTTP,包括方法名稱的命名空間,響應狀態代碼,非MIME標頭字段名稱以及標準HTTP標頭字段中的值。因爲早期的HTTP沒有爲如何部署這些命名空間中的更改定義一套一致的規則,所以這是規範工做所解決的首批問題之一。

       HTTP請求語義由請求方法名稱表示。只要能夠在客戶端,服務器和可能位於它們之間的任何中介之間共享可標準化的語義集,就容許方法擴展。不幸的是,早期的HTTP擴展,特別是HEAD方法,使HTTP響應消息的解析依賴於知道請求方法的語義。這致使了部署矛盾:若是接收方須要知道方法的語義,而後才能由中介安全地轉發,則必須先更新全部中介,而後才能部署新方法。

       經過將用於解析和轉發HTTP消息的規則與與新HTTP協議元素相關聯的語義分開來解決此部署問題。例如,HEAD是Content-Length頭字段具備除表示消息體長度以外的含義的惟一方法,而且沒有新方法能夠更改消息長度計算。GET和HEAD也是條件請求頭字段具備緩存刷新語義的惟一方法,而對於全部其餘方法,它們具備前置條件的含義。

       一樣,HTTP須要一個通用規則來解釋新的響應狀態代碼,這樣能夠部署新的響應而不會顯着損害舊的客戶端。所以,咱們擴展瞭如下規則:每一個狀態代碼屬於由其三位十進制數的第一個數字表示的類:100-199表示該消息包含臨時信息響應,200-299表示請求成功,300 -399表示請求須要重定向到另外一個資源,400-499表示客戶端發出不該該重複的錯誤,500-599表示服務器遇到錯誤,但客戶端可能會更好稍後回覆(或經過其餘服務器)。若是收件人不理解給定消息中狀態代碼的特定語義,而後他們必須以與其類中的x00代碼相同的方式對待它。與方法名稱的規則同樣,此可擴展性規則對當前體系結構提出了要求,以便預測將來的更改。所以,能夠將更改部署到現有架構上,而沒必要擔憂不良組件反應。

4.3.1.3 升級

       在HTTP / 1.1中添加Upgrade頭字段經過容許客戶端在較舊的協議流中進行通訊時宣傳其對更好協議的意願來減小部署不兼容更改的難度。升級是專門添加的,以支持選擇性地替換HTTP / 1.x與其餘將來的協議,這些協議可能對某些任務更有效。所以,HTTP不只支持內部可擴展性,還在活動鏈接期間完成自身的替換。若是服務器支持改進的協議並但願切換,則它只響應101狀態並繼續,就像在該升級的協議中接收到請求同樣。

4.3.2 自描述信息

       REST將組件之間的消息約束爲自描述,以支持交互的中間處理。可是,早期HTTP的某些方面沒法進行自我描述,包括請求中缺乏主機標識,沒法在語法上區分消息控制數據和表示元數據,沒法區分僅用於直接鏈接對等的控制數據與針對全部收件人的元數據,缺少對強制性擴展的支持,以及須要元數據來描述具備分層編碼的表示。

4.3.2.1 主機

       早期HTTP設計中最嚴重的錯誤之一是決定不發送做爲請求消息目標的完整URI,而是僅發送那些未用於設置鏈接的部分。假設服務器將根據鏈接的IP地址和TCP端口知道本身的命名權限。可是,這未能預料到單個服務器上可能存在多個命名權限,這成爲一個關鍵問題,由於Web以指數速率增加,而新域名(http URL命名空間內命名權限的基礎)遠遠超出了可用性新的IP地址。

       爲HTTP / 1.0和HTTP / 1.1定義和部署的解決方案是在請求消息的主機頭字段中包含目標URL的主機信息。此功能的部署被認爲很是重要,以致於HTTP / 1.1規範要求服務器拒絕任何不包含主機字段的HTTP / 1.1請求。結果,如今存在許多大型ISP服務器,其在單個IP地址上運行數萬個基於名稱的虛擬主機網站。

4.3.2.2 分層編碼

       HTTP繼承了其用於描述多用途Internet郵件擴展(MIME)中的表示元數據的語法。MIME不定義分層媒體類型,而是僅在Content-Type字段值中包含最外層媒體類型的標籤。然而,這防止接收者在不解碼層的狀況下肯定編碼消息的性質。早期的HTTP擴展經過在Content-Encoding字段中單獨列出外部編碼並將最內層媒體類型的標籤放在Content-Type中來解決此問題。這是一個糟糕的設計決策,由於它改變了Content-Type的語義而不改變其字段名稱,致使每當舊用戶代理遇到擴展時就會出現混淆。

       更好的解決方案是繼續將Content-Type視爲最外層媒體類型,並使用新字段來描述該類型中的嵌套類型。不幸的是,第一次擴展是在發現故障以前部署的。

       REST確實須要另一層編碼:鏈接器放置在消息上以便提升其在網絡上的可轉移性。這個新層(稱爲轉移編碼,參考MIME中的相似概念)容許對消息進行編碼以進行傳輸,而不暗示該表示是按性質編碼的。不管出於何種緣由,轉移代理均可以添加或刪除轉移編碼,而無需更改表示的語義。

4.3.2.3 語義獨立性

       如上所述,HTTP消息解析已與其語義分離。消息解析(包括查找和彙總頭字段)徹底獨立於解析頭字段內容的過程。經過這種方式,中介能夠快速處理和轉發HTTP消息,而且能夠在不破壞現有解析器的狀況下部署擴展。

4.3.2.4 運輸獨立性

       早期的HTTP,包括HTTP / 1.0的大多數實現,使用底層傳輸協議做爲發送響應消息結束信號的手段。服務器將經過關閉TCP鏈接來指示響應消息正文的結束。不幸的是,這在協議中形成了嚴重的失敗狀況:客戶端沒法區分已完成的響應和因某些錯誤的網絡故障而被截斷的響應。爲了解決這個問題,Content-Length頭字段在HTTP / 1.0中被從新定義,以指示消息體長度(以字節爲單位),每當事先知道長度,而且「chunked」傳輸編碼被引入HTTP / 1.1。

       分塊編碼容許在其生成開始時(當發送報頭字段時)大小未知的表示使其邊界由一系列塊描繪,這些塊在發送以前能夠單獨地大小。它還容許在消息末尾將元數據做爲預告片發送,從而在生成消息時在原點建立可選元數據,而不會增長響應延遲。

4.3.2.5 大小限制

       對應用層協議的靈活性的常見障礙是傾向於過分指定協議參數的大小限制。儘管在協議的實現中老是存在一些實際限制(例如,可用存儲器),可是在協議內指定那些限制將全部應用限制到相同的限制,而無論它們的實現如何。結果一般是最低公分母協議,不能超出其原始建立者的設想。

       HTTP協議對URI的長度,頭字段的長度,表示的長度或由項列表組成的任何字段值的長度沒有限制。儘管較舊的Web客戶端存在一個衆所周知的URI,其中包含超過255個字符的問題,但只須要注意HTTP規範中的問題而不是要求全部服務器都受到限制。這不會使協議最大化的緣由是受控上下文(例如Intranet)內的應用程序能夠經過替換舊組件來避免這些限制。

       雖然咱們不須要發明人爲限制,但HTTP / 1.1確實須要定義一組適當的響應狀態代碼,以指示給定協議元素什麼時候對服務器進行處理時間過長。這些響應代碼是在Request-URI條件太長,標題字段太長,正文太長的狀況下添加的。遺憾的是,客戶端沒法向服務器指示它可能具備資源限制,這在資源受限設備(例如PDA)嘗試使用HTTP而沒有特定於設備的中介調整通訊時會致使問題。

4.3.2.6 緩存限制

       因爲REST試圖平衡對高效,低延遲行爲的需求與對語義透明緩存行爲的需求,所以HTTP容許應用程序肯定緩存要求而不是將其硬編碼到協議自己中相當重要。協議要作的最重要的事情就是徹底準確地描述正在傳輸的數據,這樣就不會讓任何應用程序誤覺得它實際上有其餘東西時會有一件事情。HTTP / 1.1經過添加Cache-Control,Age,Etag和Vary頭字段來實現此目的。

4.3.2.7 內容協商

       全部資源都將請求(包括方法,標識符,請求標題字段,有時是表示)映射到響應(由狀態代碼,響應標頭字段,有時是表示)組成。當HTTP請求映射到服務器上的多個表示時,服務器能夠與客戶進行內容協商,以肯定哪一個最符合客戶的需求。這實際上比談判更像是一個「內容選擇」過程。

       雖然有幾個部署的內容協商實現,但它沒有包含在HTTP / 1.0規範中,由於在發佈時沒有可互操做的實現子集。這部分是因爲NCSA Mosaic中的實施不佳,不管資源的可轉讓性如何,都會在每一個請求的頭字段中發送1KB的偏好信息[ 125 ]。因爲遠低於全部URI的0.01%在內容中可協商,所以結果顯着增長了請求延遲以得到很是小的增益,這致使後來的瀏覽器無視HTTP / 1.0的協商功能。

       當服務器根據請求頭字段的值或上述正常請求參數外部的某些內容改變特定請求方法標識符狀態代碼組合的響應表示時,發生搶佔(服務器驅動)協商。發生這種狀況時,客戶端須要獲得通知,以便緩存能夠知道什麼時候對於未來的請求使用特定的緩存響應在語義上是透明的,而且還使得用戶代理能夠提供比一般一次發送的更詳細的首選項。它知道它們對收到的回覆有影響。HTTP / 1.1爲此目的引入了Vary頭字段。Vary只列出響應可能變化的請求標頭字段維度。

       在搶先協商中,用戶代理告訴服務器它可以接受什麼。而後,服務器應該選擇與用戶代理聲稱其功能最匹配的表示。然而,這是一個不易處理的問題,由於它不只須要關於UA將接受什麼的信息,並且還須要它接受每一個特徵的程度以及用戶打算表達的目的。例如,想要在屏幕上查看圖像的用戶可能更喜歡簡單的位圖表示,可是若是他們打算將其發送到打印機,則具備相同瀏覽器的相同用戶可能更喜歡PostScript表示。它還取決於用戶根據本身的我的內容偏好正確配置他們的瀏覽器。簡而言之,

       HTTP / 1.1增長了被動(代理驅動)協商的概念。在這種狀況下,當用戶代理請求協商的資源時,服務器以可用的表示列表進行響應。而後,用戶代理能夠根據本身的能力和目的選擇哪個最佳。關於可用表示的信息能夠經過響應數據內部的單獨表示(例如,300響應)來提供(例如,條件HTML),或者做爲「最可能」響應的補充。後者最適合Web,由於只有當用戶代理決定其餘變體之一會更好時,才須要額外的交互。反應式協商只是普通瀏覽器模型的自動反映,這意味着它能夠充分利用REST的全部性能優點。

       搶先式和被動式協商都難以傳達表示維度的實際特徵(例如,如何說瀏覽器支持HTML表而不是INSERT元素)。然而,反應式協商具備明顯的優勢,即沒必要在每一個請求上發送首選項,具備更多的上下文信息,在面對備選方案時能夠作出決策,而不是干擾緩存。

       第三種形式的協商,透明協商[ 64 ],是中間緩存表明其餘代理充當代理的許可,用於選擇更好的表示併發起檢索該表示的請求。該請求能夠經過另外一個緩存命中在內部解析,所以可能不會進行額外的網絡請求。可是,在這樣作時,它們正在執行服務器驅動的協商,所以必須添加適當的Vary信息,以便其餘出站緩存不會混淆。

4.3.3 性能

       HTTP / 1.1側重於改進組件之間通訊的語義,可是對用戶感知性能也有一些改進,儘管受到與HTTP / 1.0的語法兼容性要求的限制。

4.3.3.1 持久鏈接

       雖然早期HTTP的單個請求/響應是針對簡單實現的每一個鏈接行爲,但因爲每一個交互設置成本的開銷和TCP的慢啓動擁塞控制算法的性質,致使底層TCP傳輸的使用效率低下[ 63],125 ]。所以,提出了幾個擴展,以在單個鏈接中組合多個請求和響應。

       第一個提議是定義一組新的方法,用於在單個消息(MGET,MHEAD等)中封裝多個請求,並將響應做爲MIME多部分返回。這被拒絕了,由於它違反了幾個REST約束。首先,客戶端須要知道在第一個請求被寫入網絡以前它想要打包的全部請求,由於請求主體必須由初始請求頭字段中設置的內容長度字段進行長度分隔。其次,中介必須提取每條消息,以肯定它能夠在本地知足哪些消息。最後,它有效地使請求方法的數量加倍,並使選擇性地拒絕訪問某些方法的機制複雜化。

       相反,咱們採用了一種持久鏈接形式,它使用長度分隔的消息,以便在單個鏈接上發送多個HTTP消息。對於HTTP / 1.0,這是使用Connection頭字段中的「keep-alive」指令完成的。不幸的是,這一般不起做用,由於標題字段能夠由中介轉發給其餘不瞭解保持活動的中介,從而致使死鎖條件。HTTP / 1.1最終決定使持久鏈接成爲默認值,從而經過HTTP版本值代表它們的存在,而且僅使用connection-directive「close」來反轉默認值。

       值得注意的是,只有在將HTTP消息從新定義爲自描述且獨立於底層傳輸協議以後,才能實現持久鏈接。

4.3.3.2 直寫緩存

       HTTP不支持回寫緩存。HTTP緩存不能假定經過它寫入的內容與從該資源的後續請求可檢索的內容相同,所以它沒法緩存PUT請求主體並將其重用於之後的GET響應。此規則有兩個緣由:1)可能在幕後生成元數據,2)沒法從PUT請求肯定之後GET請求的訪問控制。可是,因爲使用Web的寫入操做極少,所以缺乏回寫式高速緩存不會對性能產生重大影響。

4.3.4 HTTP中的REST不匹配

       HTTP中存在一些架構與REST不匹配,一些是因爲部署在標準流程外部的第三方擴展,另外一些是因爲必須保持與部署的HTTP / 1.0組件兼容。

4.3.4.1 區分非權威影響

       HTTP中仍然存在的一個缺點是,沒有一致的機制來區分由原始服務器響應當前請求而生成的權威響應,以及從中間設備或緩存獲取的非權威響應,而無需訪問原始服務器。這種區別對於須要權威響應的應用程序很是重要,例如健康行業中使用的安全關鍵信息設備,以及返回錯誤響應而且客戶端想知道錯誤是否源於原點的那些時間或某些中間人。嘗試使用其餘狀態代碼解決此問題並未成功,由於權威性質一般與響應狀態正交。

       HTTP / 1.1確實添加了一種機制來控制緩存行爲,從而能夠指示對權威響應的需求。請求消息上的「no-cache」指令要求任何緩存將請求轉發到源服務器,即便它具備所請求內容的緩存副本。這容許客戶端刷新已知已損壞或過期的緩存副本。可是,按期使用此字段會干擾緩存的性能優點。更通用的解決方案是,只要操做不會致使聯繫原始服務器,就要求將響應標記爲非權威。爲此目的(和其餘)在HTTP / 1.1中定義了一個警告響應頭字段,但它在實踐中還沒有普遍實現。

4.3.4.2 Cookies

       舉例說明對協議進行了不適當的擴展以支持與通用接口所需屬性相矛盾的功能,即以HTTP cookie的形式引入站點範圍的狀態信息。Cookie交互沒法與REST的應用程序狀態模型匹配,一般會致使典型瀏覽器應用程序混淆。

       HTTP cookie是不透明的數據,能夠由源服務器分配給用戶代理,方法是將其包含在Set-Cookie響應頭字段中,目的是用戶代理應該在未來對該服務器的全部請求中包含相同的cookie直到它被替換或過時。此類cookie一般包含一組特定於用戶的配置選項,或者在未來的請求中與服務器數據庫匹配的令牌。問題在於,cookie被定義爲附加到對給定資源標識符集的任何將來請求,一般包含整個站點,而不是與瀏覽器上的特定應用程序狀態(當前呈現的表示集合)相關聯。當瀏覽器的歷史功能(「返回」)隨後用於備份到cookie反映的視圖以前的視圖,瀏覽器的應用程序狀態再也不與cookie中表示的存儲狀態匹配。所以,發送到同一服務器的下一個請求將包含一個錯誤表示當前應用程序上下文的cookie,從而致使雙方混淆。

       Cookie還違反了REST,由於它們容許在沒有充分識別其語義的狀況下傳遞數據,從而成爲安全和隱私的關注點。Cookie與Referer [sic]標題字段的組合使得跟蹤用戶在站點之間瀏覽時成爲可能。

       所以,Web上基於cookie的應用程序永遠不可靠。應該經過匿名身份驗證和真正的客戶端狀態來完成相同的功能。經過明智地使用上下文設置URI而不是cookie,能夠更有效地實現涉及首選項的狀態機制,其中明智意味着每一個狀態一個URI而不是因爲嵌入用戶id而無限數量的URI。一樣,經過在超媒體數據格式中定義購物項的語義,容許用戶代理選擇和存儲這些項,能夠更有效地實現使用cookie來識別服務器端數據庫中的用戶特定「購物籃」。在他們本身的客戶端購物籃中,配有一個URI,用於在客戶準備購買時簽出。

4.3.4.3 強制擴展

       HTTP標頭字段名稱能夠隨意擴展,但只有在它們包含的信息不是正確理解消息時才須要擴展。強制標頭字段擴展須要主要協議修訂或對方法語義的實質性更改,例如[ 94]。這是現代Web架構的一個方面,它還沒有與REST架構風格的自描述消息傳遞約束相匹配,主要是由於在現有HTTP語法中實現強制擴展框架的成本超過了咱們可能從中得到的任何明顯好處。強制性擴展。可是,當對語法的向後兼容性的現有約束再也不適用時,指望在HTTP的下一個主要修訂版中支持必需的字段名稱擴展是合理的。

4.3.4.4 混合元數據

       HTTP旨在經過網絡鏈接擴展通用鏈接器接口。所以,它旨在匹配該接口的特徵,包括將參數描繪爲控制數據,元數據和表示。可是,HTTP / 1.x協議系列的兩個最重要的限制是它沒法在語法上區分表示元數據和消息控制信息(都做爲頭字段傳輸),而且不容許元數據有效地分層以實現消息完整性檢查。

       REST在標準化過程的早期階段將這些限制在協議中,預計它們會致使其餘功能部署中的問題,例如持久鏈接和摘要式身份驗證。開發了變通方法,包括添加Connection頭字段以識別中間人轉發不安全的每鏈接控制數據,以及標頭字段摘要的規範處理算法。

4.3.4.5 MIME語法

       HTTP繼承了MIME 的消息語法,以保持與其餘Internet協議的通用性,並重用許多標準化字段來描述消息中的媒體類型。不幸的是,MIME和HTTP具備很是不一樣的目標,而且語法僅針對MIME的目標而設計。

       在MIME中,用戶代理正在向未知的接收者發送一堆信息,這些信息旨在被視爲一個連貫的總體,而這些信息從未直接與之交互。MIME假定代理但願在一條消息中發送全部信息,由於經過Internet郵件發送多條消息的效率較低。所以,構造MIME語法以將郵件打包在部件或多部件中,這與郵政運營商將包裹包裝在額外紙張中的方式很是類似。

       在HTTP中,除了安全封裝或打包存檔以外,在單個消息中打包不一樣對象沒有任何意義,由於對還沒有緩存的那些文檔進行單獨請求更有效。所以,HTTP應用程序使用HTML等媒體類型做爲對「包」的引用的容器 - 而後用戶代理能夠選擇要做爲單獨請求檢索的包的哪些部分。儘管HTTP可能使用多部分包,其中第一部分以後僅包含非URI資源,但對它的需求並不大。

       MIME語法的問題在於它假設傳輸是有損的,故意破壞換行符和內容長度之類的東西。所以,對於不基於有損傳輸的任何系統,語法都是冗長且低效的,這使得它不適合HTTP。因爲HTTP / 1.1具備支持不兼容協議部署的能力,所以對於下一個主要版本的HTTP,保留MIME語法不是必需的,即便它可能會繼續使用許多標準化協議元素來表示元數據。

4.3.5 匹配對請求的響應

       在描述哪一個響應屬於哪一個請求時,HTTP消息沒法自我描述。早期的HTTP基於每一個鏈接的單個請求和響應,所以不須要消息控制數據將響應綁定回調用它的請求。所以,請求的排序決定了響應的順序,這意味着HTTP依賴於傳輸鏈接來肯定匹配。

       HTTP / 1.1雖然被定義爲獨立於傳輸協議,但仍假定通訊發生在同步傳輸上。經過添加請求標識符,能夠輕鬆擴展它以處理異步傳輸,例如電子郵件。這種擴展對於廣播或多播狀況下的代理是有用的,其中能夠在與請求的信道不一樣的信道上接收響應。此外,在許多請求待處理的狀況下,它將容許服務器選擇響應被傳送的順序,從而首先發送更小或更重要的響應。

4.4 技術轉讓

       雖然REST對Web標準的創做有最直接的影響,可是經過以商業級實現的形式部署標準來驗證其做爲架構設計模型的使用。

4.4.1 libwww-perl的實踐經驗

       我參與Web標準的定義始於維護機器人MOMspider 及其相關協議庫libwww-perl的開發。以Tim Berners-Lee開發的原始libwww和CERN的WWW項目爲模型,libwww-perl提供了一個統一的界面,用於爲使用Perl語言編寫的客戶端應用程序發出Web請求和解釋Web響應。它是第一個獨立於原始CERN項目開發的Web協議庫,反映了Web接口比舊代碼庫中更現代的解釋。該接口成爲設計REST的基礎。

       libwww-perl由單個請求接口組成,該接口使用Perl的自我評估代碼功能,根據請求的URI方案動態加載適當的傳輸協議包。例如,當要求在URL http://www.ebuilt.com/上發出「GET」請求時,libwww-perl將從URL(「http」)中提取該方案並使用它來構建一個調用到wwwhttp'request(),使用全部類型資源(HTTP,FTP,WAIS,本地文件等)共有的接口。爲了實現這個通用接口,庫以與HTTP代理大體相同的方式處理全部調用。它提供了一個使用Perl數據結構的接口,它具備與HTTP請求相同的語義,而無論資源的類型如何。

       libwww-perl展現了通用接口的優勢。在最初發布的一年內,超過600名獨立軟件開發人員使用該庫建立本身的客戶端工具,從命令行下載腳本到成熟的瀏覽器。它目前是大多數Web系統管理工具的基礎。

4.4.2 Apache的實踐經驗

       因爲HTTP的規範工做開始採用完整規範的形式,咱們須要服務器軟件,既能夠有效地演示建議的標準協議,也能夠做爲有價值擴展的測試平臺。當時,最受歡迎的HTTP服務器(httpd)是由Rob McCool在伊利諾伊大學厄巴納 - 香檳分校(NCSA)的國家超級計算應用中心開發的公共領域軟件。然而,在1994年中期Rob離開NCSA後,開發工做陷入停滯,許多網站管理員開發了本身的擴展和錯誤修復,須要共同分發。咱們一羣人建立了一個郵件列表,目的是將咱們的更改做爲原始來源的「補丁」進行協調。在此過程當中,咱們建立了Apache HTTP Server Project 。

       Apache項目是一項協做軟件開發工做,旨在爲HTTP服務器建立一個強大的,商業級的,功能齊全的開源軟件實現。該項目由位於世界各地的一組志願者共同管理,使用互聯網和網絡來交流,規劃和開發服務器及其相關文檔。這些志願者被稱爲Apache Group。最近,該組織成立了非營利組織Apache Software Foundation,做爲支持Apache開源項目持續開發的法律和金融傘形組織。

       Apache以其強大的行爲而聞名,以響應互聯網服務的各類需求以及嚴格實施HTTP協議標準。我在Apache Group中擔任「協議警察」,爲核心HTTP解析函數編寫代碼,經過解釋標準支持其餘人的工做,並充當Apache開發人員對「正確實施方法」的觀點的倡導者HTTP「在標準論壇內。本章中描述的許多課程都是在Apache項目中建立和測試HTTP的各類實現,並將協議背後的理論置於Apache Group的批判性審覈中。

       Apache httpd被普遍認爲是最成功的軟件項目之一,也是第一個主導市場的開源軟件產品之一,其中存在重大的商業競爭。2000年7月Netcraft對公共互聯網網站的調查發現,基於Apache軟件的網站超過2000萬個,佔全部被調查網站的65%以上[http://www.netcraft.com/survey/]。Apache是第一個支持HTTP / 1.1協議的主要服務器,一般被認爲是測試全部客戶端軟件的參考實現。Apache Group得到1999年ACM軟件系統獎,以表彰咱們對Web架構標準的影響。

4.4.3 部署URI和HTTP/1.1兼容軟件

       除了Apache以外,許多其餘商業和開源項目都採用並部署了基於現代Web架構協議的軟件產品。雖然這可能只是巧合,但微軟Internet Explorer在第一個實現HTTP / 1.1客戶端標準的主要瀏覽器以後不久便在Web瀏覽器市場份額中超越了Netscape Navigator。此外,在標準化過程當中定義的許多單獨的HTTP擴展(例如Host頭字段)如今已經達到了通用部署。

       REST架構風格成功地指導了現代Web架構的設計和部署。到目前爲止,新標準的引入並無出現重大問題,儘管它們與傳統的Web應用程序一塊兒進行了逐步和分散的部署。此外,新標準對Web的健壯性產生了積極影響,並經過緩存層次結構和內容分發網絡實現了提升用戶感知性能的新方法。

4.5 架構課程

       從現代Web架構和REST識別的問題中能夠學到許多通常的架構課程。

4.5.1 基於網絡的API優勢

       現代Web與其餘中間件的區別在於它使用HTTP做爲基於網絡的應用程序編程接口(API)的方式。狀況並不是老是如此。早期的Web設計使用了一個庫包CERN libwww做爲全部客戶端和服務器的單一實現庫。CERN libwww提供了一個基於庫的API,用於構建可互操做的Web組件。

       基於庫的API提供了一組代碼入口點和相關的符號/參數集,以便程序員能夠使用其餘人的代碼來執行維護相似系統之間的實際接口的髒工做,前提是程序員遵循架構和語言該代碼附帶的限制。假設通訊的全部方面都使用相同的API,所以接口的內部僅對API開發人員而非應用程序開發人員很重要。

       單一圖書館方法於1993年結束,由於它與參與開發網絡的組織的社會動態不匹配。當NCSA的團隊經過比CERN更大的開發團隊增長Web開發的速度時,libwww源代碼被「分叉」(分紅單獨維護的代碼庫),以便NCSA的人們沒必要等待歐洲核子研究中心追趕他們的進步。與此同時,像我這樣的獨立開發人員開始爲CERN代碼還沒有支持的語言和平臺開發協議庫。Web的設計必須從參考協議庫的開發轉向基於網絡的API的開發,在多個平臺和實現之間擴展Web的所需語義。

       基於網絡的API是一種線上語法,具備定義的語義,用於應用程序交互。除了須要讀取/寫入網絡以外,基於網絡的API不會對應用程序代碼施加任何限制,但會對能夠經過接口有效通訊的語義集施加限制。從好的方面來講,性能僅受協議設計的限制,而不受該設計的任何特定實現的限制。

       基於庫的API爲程序員提供了更多功能,但這樣作會產生比任何一個系統所需的更多複雜性和包袱,在異構網絡中的可移植性更低,而且老是致使通用性優於性能。做爲一種反作用,它還會致使懶惰的開發(將全部內容歸咎於API代碼)以及未能解釋通訊中其餘方的非合做行爲。

       可是,重要的是要記住,任何架構都涉及各類層,包括現代Web的層。像Web這樣的系統使用一個庫API(套接字)來訪問幾個基於網絡的API(例如,HTTP和FTP),但套接字API自己位於應用層之下。一樣,libwww是一個有趣的交叉品種,它已經演變成基於庫的API,用於訪問基於網絡的API,所以提供可重用的代碼,而不假設其餘通訊應用程序也在使用libwww。

       這與CORBA 等中間件造成鮮明對比。因爲CORBA只容許經過ORB進行通訊,所以其傳輸協議IIOP對於各方的通訊過多。HTTP請求消息包括標準化應用程序語義,而IIOP消息則不包括。IIOP中的「請求」令牌僅提供方向性,以便ORB能夠根據ORB自己是否應該回復(例如,「LocateRequest」)或者它是否將被對象解釋來路由它。語義由對象鍵和操做的組合表示,它們是特定於對象的,而不是跨全部對象的標準化。

       獨立開發人員能夠在不使用相同ORB的狀況下生成與IIOP請求相同的位,但這些位自己由CORBA API及其接口定義語言(IDL)定義。它們須要由IDL編譯器生成的UUID,反映IDL操做簽名的結構化二進制內容,以及根據IDL規範定義的回覆數據類型。所以,語義不是由網絡接口(IIOP)定義的,而是由對象的IDL規範定義的。這是不是一件好事取決於應用程序 - 對於分佈式對象,它是必需的,對於Web來講它不是。

       爲何這很重要?由於它區分了一個系統,在這個系統中,網絡中介能夠是有效的代理,而系統最多隻能是路由器。

       在將消息解釋爲單元或流時,也能夠看到這種差別。HTTP容許收件人或發件人本身決定。CORBA IDL甚至不容許流(可是),但即便它擴展到支持流,通訊的兩端也將綁定到相同的API,而不是自由使用任何最適合其類型的應用。

4.5.2 HTTP不是RPC

       人們常常錯誤地將HTTP稱爲遠程過程調用(RPC)機制,由於它涉及請求和響應。RPC與其餘形式的基於網絡的應用程序通訊的區別在於在遠程機器上調用過程的概念,其中協議識別過程並向其傳遞一組固定的參數,而後等待在一個參數內提供的答案。使用相同的接口返回消息。遠程方法調用(RMI)相似,只是該過程被標識爲{object,method}元組而不是服務過程。Brokered RMI增長了名稱服務間接和其餘一些技巧,但界面基本相同。

       HTTP與RPC的區別不在於語法。它甚至不是使用流做爲參數得到的不一樣特性,但這有助於解釋爲何現有的RPC機制不能用於Web。使HTTP明顯不一樣於RPC的緣由是請求是使用具備標準語義的通用接口定向到資源的,這些語義能夠由中間人解釋,也能夠由發起服務的機器解釋。結果是一個應用程序,它容許獨立於信息源的轉換和間接層,這對於Internet規模,多組織,沒法擴展的信息系統很是有用。相反,RPC機制是根據語言API定義的,而不是基於網絡的應用程序。

4.5.3 HTTP不是傳輸協議

       HTTP不是設計爲傳輸協議。它是一種傳輸協議,其中消息經過傳輸和操縱這些資源的表示對資源執行操做來反映Web體系結構的語義。使用這個很是簡單的接口能夠實現普遍的功能,可是須要遵循接口才能使HTTP語義對中間人保持可見。

       這就是HTTP經過防火牆的緣由。除了WebDAV以外,大多數最近提出的HTTP擴展只是使用HTTP做爲一種經過防火牆移動其餘應用程序協議的方法,這是一個根本誤導的想法。它不只沒有達到防火牆的目的,並且從長遠來看也不會起做用,由於防火牆廠商只須要執行額外的協議過濾。所以,在HTTP之上進行這些擴展是沒有意義的,由於在這種狀況下,HTTP完成的惟一事情是增長遺留語法的開銷。HTTP的真正應用將協議用戶的動做映射到能夠使用HTTP語義表達的東西,從而爲服務建立基於網絡的API,代理和中介能夠在不知道應用程序的狀況下理解這些API。

4.5.4 媒體類型的設計

       REST對建築風格來講不一樣尋常的一個方面是它影響Web架構中數據元素定義的程度。

4.5.4.1 基於網絡的系統中的應用狀態

       REST定義了一個預期的應用程序行爲模型,它支持簡單而強大的應用程序,這些應用程序在很大程度上不受困擾大多數基於網絡的應用程序的部分。 可是,這並不能阻止應用程序開發人員引入違反該模型的功能。最多見的違規是關於應用程序狀態和無狀態交互的約束。

       因爲錯誤放置應用程序狀態而致使的架構不匹配不只限於HTTP cookie。對超文本標記語言(HTML)引入「框架」引發了相似的混淆。框架容許將瀏覽器窗口劃分爲子窗口,每一個窗口都有本身的導航狀態。子窗口中的連接選擇與正常轉換沒法區分,但生成的響應表示在子窗口中呈現,而不是在完整的瀏覽器應用程序工做空間中呈現。這很好,前提是沒有連接退出用於子窗口處理的信息領域,可是當它確實發生時,用戶發現本身正在查看一個楔入另外一個應用程序的子上下文中的應用程序。

       對於幀和cookie,失敗的緣由是提供了用戶代理沒法管理或解釋的間接應用程序狀態。將此信息置於主要表示中的設計,從而通知用戶代理如何管理指定的資源域的超媒體工做空間,能夠在不違反REST約束的狀況下完成相同的任務,同時實現更好的用戶界面和減小對緩存的干擾。

4.5.4.2 增量處理

       經過將延遲減小做爲架構目標,REST能夠根據用戶感知的性能區分媒體類型(表示的數據格式)。增量渲染的大小,結構和容量都會影響傳輸,呈現和操做表示媒體類型時遇到的延遲,所以會顯着影響系統性能。

       HTML是媒體類型的一個示例,在大多數狀況下,它具備良好的延遲特性。早期HTML中的信息能夠在收到時呈現,由於全部渲染信息都是早期可用的 - 在構成HTML的一小組標記標記的標準化定義中。可是,有些方面的HTML設計不適合延遲。示例包括:在文檔的HEAD中放置嵌入的元數據,致使在呈現引擎能夠讀取顯示對用戶有用的部分以前須要傳輸和處理的可選信息[ 93]。嵌入圖像沒有渲染大小提示,要求在顯示周圍HTML的其他部分以前接收圖像的前幾個字節(包含佈局大小的部分); 動態調整大小的表列,要求渲染器在開始顯示頂部以前讀取並肯定整個表的大小; 而且,關於解析格式錯誤的標記語法的惰性規則,一般要求渲染引擎在肯定缺乏一個鍵標記字符以前解析整個文件。

4.5.4.3 Java與JavaScript

       REST還可用於深刻了解爲何某些媒體類型在Web架構中的使用率高於其餘媒體類型,即便開發者意見的平衡不利於他們。Java applet與JavaScript的狀況就是一個例子。

       Java TM 是一種流行的編程語言,最初是爲電視機頂盒中的應用程序開發的,可是當它被引入Web做爲實現按需代碼功能的手段時,它首先得到了聲名狼借。儘管該語言獲得了其全部者Sun Microsystems,Inc。的大量媒體支持,以及尋求替代C ++語言的軟件開發人員的好評如潮,但它未能被應用程序開發人員普遍採用,以知足代碼需求。在網絡內。

       在Java推出後不久,Netscape Communications Corporation的開發人員爲嵌入式按需代碼建立了一種單獨的語言,最初稱爲LiveScript,但後來因營銷緣由改成JavaScript名稱(這兩種語言除此以外幾乎沒有共同點)。雖然最初被嘲笑嵌入HTML而且與正確的HTML語法不兼容,但自從推出以來,JavaScript的使用率一直在穩步增加。

       問題是:爲何JavaScript在Web上比Java更成功?它固然不是由於它的技術質量做爲一種語言,由於與Java相比,它的語法和執行環境都被認爲是差的。這也不是由於市場營銷:Sun在這方面遠遠超過Netscape,而且還在繼續這樣作。這並非由於語言的任何固有特性,由於Java在全部其餘編程領域(獨立應用程序,servlet等)中比JavaScript更成功。爲了更好地理解這種差別的緣由,咱們須要根據其特性評估Java做爲REST中的表示媒體類型。

       JavaScript更適合Web技術的部署模型。它的入門門檻要低得多,不管是做爲一種語言的總體複雜性仍是新手程序員整理第一段工做代碼所需的初始工做量。JavaScript對交互的可見性影響也較小。獨立組織能夠像複製HTML同樣閱讀,驗證和複製JavaScript源代碼。相反,Java是做爲二進制打包存檔下載的 - 所以用戶能夠信任Java執行環境中的安全限制。一樣,Java還有許多在安全環境中被認爲有問題的功能,包括將RMI請求發送回原始服務器的能力。RMI不支持中介機構的可見性。

       然而,二者之間最重要的區別多是JavaScript致使較少的用戶感知延遲。JavaScript一般做爲主要表示的一部分下載,而Java applet則須要單獨的請求。Java代碼一旦轉換爲字節代碼格式,就比典型的JavaScript大得多。最後,雖然能夠在下載HTML頁面的其他部分時執行JavaScript,但Java要求在應用程序開始以前下載並安裝完整的類文件包。所以,Java不支持增量渲染。

       一旦語言的特徵與REST約束背後的基本原理相同,就能夠更容易地根據現代Web架構中的行爲來評估技術。

5 總結

       REST是一組協調的體系結構約束,旨在最大限度地減小延遲和網絡通訊,同時最大限度地提升組件實現的獨立性和可伸縮性。這是經過在鏈接器語義上設置約束來實現的,其中其餘樣式專一於組件語義。REST支持交互的緩存和重用,組件的動態可替代性以及中介處理操做,從而知足Internet規模分佈式超媒體系統的需求。

       現代Web是REST風格體系結構的一個實例。雖然基於Web的應用程序能夠包括對其餘交互方式的訪問,但其協議和性能問題的核心焦點是分佈式超媒體。REST僅詳細說明了體系結構中那些被認爲對於Internet規模的分佈式超媒體交互相當重要的部分。能夠看到Web體系結構的改進領域,其中現有協議沒法表達組件交互的全部潛在語義,而且能夠在不改變體系結構功能的狀況下用更有效的表單替換語法的細節。一樣,能夠將建議的擴展與REST進行比較,以肯定它們是否適合架構。

       在理想的世界中,軟件系統的實現與其設計徹底匹配。現代Web體系結構的某些功能確實與REST中的設計標準徹底對應,例如使用URI做爲資源標識符以及使用Internet媒體類型來標識表示數據格式。然而,現代Web協議的某些方面儘管存在架構設計,但因爲遺留實驗失敗(但必須保留以便向後兼容)和開發人員在不知道架構風格的狀況下部署的擴展。REST提供的模型不只用於開發和評估新功能,還用於識別和理解損壞的功能。

       萬維網能夠說是世界上最大的分佈式應用程序。瞭解Web底層的關鍵架構原則能夠幫助解釋其技術成功,並可能致使其餘分佈式應用程序的改進,特別是那些適合相同或相似交互方法的應用程序。REST有助於提供現代Web軟件體系結構背後的基本原理,以及如何在設計和評估真實軟件系統時系統地應用軟件工程原理的重要教訓。

       對於基於網絡的應用程序,系統性能主要由網絡通訊決定。對於分佈式超媒體系統,組件交互包括大粒度數據傳輸而不是計算密集型任務。REST風格是爲知足這些需求而開發的。它專一於資源和表示的通用鏈接器接口,實現了組件的中間處理,緩存和可替代性,這反過來又容許基於Web的應用程序從1994年的100,000個請求擴展到1999年的600,000,000個請求。

       REST體系結構樣式已經過HTTP / 1.0 和HTTP / 1.1標準的六年開發,URI和相對URL標準的詳細闡述以及幾十個成功部署的驗證在現代Web架構中獨立開發的商業級軟件系統。它既是設計指導的模型,也是Web協議架構擴展的酸性測試。

       將來的工做將側重於將架構指南擴展到開發HTTP / 1.x協議系列的替代品,使用更高效的標記化語法,但不會丟失REST標識的理想屬性。無線設備的需求與REST背後的原理具備許多共同特徵,將促進應用程序級協議設計和涉及活動中介的體系結構的進一步加強。還有一些興趣是擴展REST以考慮可變請求優先級,差別化服務質量以及由連續數據流組成的表示,例如由廣播音頻和視頻源生成的數據流。

參考

[1]Roy Thomas Fielding,Architectural Styles and the Design of Network-based Software Architectures[D], CALIFORNIA,UNIVERSITY OF CALIFORNIA,2000
文章連接:https://www.ics.uci.edu/~fielding/pubs/dissertation/top.htm

相關文章
相關標籤/搜索