AJAX與REST

來源:互聯網
上載者:User

2006 年 11 月 09 日

伺服器端 Web 應用程式因採用富應用程式模型和交付個人化內容而具備了融入式(immersive) 的特點,這種特點越突出,應用程式架構對 Web 架構風格 REST(Representational State Transfer)的違背就越多。這種違背會降低應用程式的延展性,增加系統複雜性。通過與 REST 相互協調,Ajax 架構將使融入式 Web 應用程式消除這些負面影響,盡享 REST 那些出色的特性。

在短短 15 年中,World Wide Web 已經從一項研究實驗成長為現代社會的技術支柱。最初發明 Web 的目的是使人們可以輕鬆發布和連結資訊,現在它已經發展為軟體應用程式的可行平台。但隨著應用程式通過使用富應用程式模型和產生個人化內容而獲得了更多的融入性,它們的架構對 Web 架構風格 REST(Representational State Transfer)的違背也越來越多。這種違背會降低應用程式的延展性,增加系統複雜性。

新興的 Ajax Web 客戶機架構風格讓融入式 Web 應用程式與 REST 架構風格協調一致。使它們可以盡享 REST 那些出色的特性,同時又消除了應用程式違背 REST 準則時帶來的不良特性。本文將介紹為融入式 Web 應用程式成功結合 Ajax 和 REST 的方法與原因。

請訪問 Ajax 技術資源中心,這是有關 Ajax 編程模型資訊的一站式中心,包括很多文檔、教程、論壇、blog、wiki 和新聞。任何新資訊都能在這裡找到。

REST:Web 架構

儘管 World Wide Web 是在數十年的相關研究基礎上建立起來的,但它的有效誕生日期是 1990 年 12 月,當時 Tim Berners-Lee 完成了 Web 主要組件的工作原型:統一資源識別項(URI)、HTTP、HTML、瀏覽器和伺服器。Web 被迅猛採用,遠遠超過了先驅者們的預期。在 Roy Fielding 最出名的系列文章中(請參看 參考資料),他描述了自己當時的心情:

“儘管對其成功感到興奮不已,但是 Internet 開發人員社區逐漸開始擔心,Web 使用的這種快速增長,以及早期 HTTP 的一些拙劣的網路特性,會快速壓倒 Internet 基礎設施所能承擔的容量,從而導致突然的崩塌。”

“一種架構在設計時就應該考慮到一組特性,讓它可以滿足甚至超越系統的需求。忽略這些特性可能會導致後期變更幹擾整個架構,就像是使用一扇落地窗去取代承重牆會破壞整個建築結構的可靠性。” —— Roy Fielding

Fielding 和其他人對 Web 架構及其是否能夠足以支援各種擴充和用法重新進行了審視。這種重新審視的有形結果包括更新諸如 URI 和 HTTP 之類的一些重要標準。這種重新審視還獲得了一些無形但卻非常有意義的結果:為超級媒體應用程式確定了一種新的架構風格,Fielding 將其命名為 REST(Representational State Transfer)。Fielding 斷言,使用且符合 REST 設計約束的 Web 上部署的組件可以充分利用 Web 的有用特性。他還警告說,違背 REST 準則的 Web 元件都將無法利用這些優點。

早期時,大部分 Web 網站和簡單的 Web 應用程式實際上都是遵守 REST 準則的。但是隨著融入式 Web 應用程式的日益普及,Web 應用程式架構逐漸開始背離 REST 準則了,此後因果迴圈,情況日益惡化。融入式伺服器端 Web 架構的問題很難分析清楚,因為在使用這種架構風格的十年中,已經建立起這樣一種信仰:這些問題都是 Web 應用程式架構所固有的。實際上,這並非是 Web 應用程式架構的問題。而是由伺服器端 Web 應用程式架構風格所產生的問題。要打破這種偏見,我們來回顧一下整個架構是如何發展到現在這種狀態的,這會很有協助。我們將說明為什麼在 Ajax 應用程式建立在商業上可行之後,過去接受的很多假設現在都不再成立了。

 



回頁首

 

Web 應用程式的簡史

Berners-Lee 創造了 Web,最初是將 Web 作為研究人員遠程共用文檔和在文檔之間建立簡單連結以加速知識和思想傳播的一種手段。然而,URI 標準的架構特徵很快實現了除靜態檔案之外更多內容的共用。

提供靜態文檔的 Web 網站

Web 上最早的內容由一些靜態 HTML 文檔組成,其中有很多到其他靜態文檔的連結, 1 所示:

圖 1. 提供靜態文檔的 Web 網站

REST 使靜態文檔的檢索極其高效、可伸縮,這是因為它們可以根據 URI 和最後修改日期來輕鬆緩衝。很快開發人員就超越了靜態文檔的領域,開始動態文檔的提供。

早期的動態 Web 應用程式

Berners-Lee 和其他人設計了 URI 標準,為資源的統一唯一標識提供支援,同時使其表示(HTML、文本等)根據 Web 客戶機(通常是 網頁瀏覽器)和 Web 服務器之間的協商結果而變化。由於 URI 將資源標識和資源的底層儲存機制區分開來,因此 Web 開發人員可以建立一些程式,使之檢查 URI 文法,並動態產生文檔,將預先定義的 UI 元素和動態檢索的資料(通常是從關聯式資料庫中)合并在一起, 2 所示。儘管這些文檔是產生的,但是它們的緩衝特徵與靜態檔案的完全相同。

圖 2. 以嵌入 HTML 範本代碼形式提供資料庫記錄的 Web 網站

此類早期應用程式的一個簡單例子是統一目錄 Web 應用程式。這種應用程式通常以如下方式工作:

  1. 使用者在 Web 表單中輸入名字(例如,Bill Higgins),並單擊提交按鈕。
  2. 表單根據輸入的名字建立一個 URI,並從伺服器上請求這個 URI 的內容(例如 GET http://psu.edu/Directory/Bill+Higgins)。
  3. 伺服器檢查這個 URI,並使用這個學生的電話號碼和地址來產生一個 Web 頁面。
  4. 伺服器將所產生的頁面發回到使用者的瀏覽器上。

這種互動的一個重要特性是它是等冪的(idempotent),也就是說除非底層資源發生變化(例如 Bill 修改了自己的電話號碼),否則同一請求的結果總是相同的。這意味著瀏覽器或Proxy 伺服器都可以在本地對 Bill Higgins 的文檔進行緩衝,只要底層資源沒有發生變化,那就可以從本機快取中檢索資源,而不再需要從遠程伺服器檢索。這種方法能提高使用者感受到的響應性,並增加系統整體效率和延展性。這些早期的動態 Web 應用程式可以很好地工作,將大量的資訊送至使用者指尖。

融入式 Web 應用程式

下一代 Web 應用程式的目標就是高度融入,提供個人化的內容和富應用程式模型。在過去十年中,Web 開發人員成功建立了這些融入式應用程式。一個非常恰當的例子是 Amazon.com 電子商務網站。當使用者與 Amazon Web 應用程式進行互動時,它會建立複雜的客戶頁面來推薦有針對性的商品,顯示瀏覽歷程記錄,並顯示使用者購物車中商品的價格。

 



回頁首

 

融入式伺服器端應用程式和 REST

融入式 Web 應用程式確實非常有用,但伺服器端的融入式 Web 應用程式風格從根本上來說是不符合 REST 架構準則的。具體來說,它違背了一項關鍵的 REST 約束,並且沒有利用 REST 最為重要的一些優點,因此又產生了一組新問題。

違背了 “無狀態服務器” 約束

REST 的 “客戶機-無狀態-伺服器” 約束禁止在伺服器上儲存工作階段狀態。符合這一約束進行設計可以提高系統的可見度、可靠性和延展性。但是融入式伺服器端 Web 應用程式希望能夠為單個使用者提供大量個人化內容,因此必須在兩種設計之間作出選擇。第一種設計要在每個客戶機請求中都發送大量狀態資訊,因此每個請求都完整地保留了內容相關的內容,伺服器是無狀態的。第二種解決方案表面上來看比較簡單,應用程式開發人員和中介軟體供應商都比較傾向於這種方法,它只是簡單地發送一個使用者標識,並在伺服器端為這個標識關聯一個 “使用者會話”( 3 所示)。第二種設計直接違背了客戶機-無狀態-伺服器約束。儘管它確實可以實現我們想要的使用者功能(具體來說就是指個人化),但卻對這個架構進行了極大的改動。

圖 3. 融入式伺服器端 Web 應用程式,其中包含了大量伺服器端工作階段狀態

Java Servlet 的 HttpSession API 正是一個此類變動的例子。HttpSession 讓我們可以在狀態和特定使用者之間建立關聯。這個 API 看起來對於開發新手非常簡單。實際上,它似乎可以將任何對象儲存到 HttpSession 中,並且不需要自己實現任何特定的尋找邏輯就可以將這些對象取出來。但是當我們開始在 HttpSession 中放入更多個物件時,就會開始注意到我們的應用伺服器要佔用的記憶體和處理資源越來越多。很快我們就確定自己需要將應用程式部署到叢集環境中來應對日益增加的資源需求。然後就會認識到,要讓 HttpSession 在叢集環境中工作,每個對象都必須實現 Java 的 Serializable 介面,以使會話資料能夠在叢集環境中的伺服器間傳遞。然後必須確定應用伺服器在關機/重啟過程中是否要繼續維護會話資料。很快您就會質疑,違背客戶機-無狀態-伺服器約束是否真的是一個好主意。(實際上,很多開發人員都不瞭解這個約束。)

使分布式緩衝變為不可能

融入式伺服器端 Web 應用程式的第二個嚴重後果在於:它實際上不能利用 REST 的第一類支援進行資源緩衝。引用 Fielding 的話來說,“添加緩衝約束的優點是可以部分或完全避免某些互動操作,從而可以通過減少一系列互動的平均延遲來提高效率、延展性以及使用者可以感受到的效能。不過這樣做的代價是如果緩衝中的陳舊資料與通過將請求直接發送給伺服器而獲得的資料有很大區別,那麼緩衝的可靠性就降低了。”

我們可以將融入式 Web 應用程式近似地看作一個活動實體,它會根據使用者提供的新輸入內容、其他人輸入的新內容以及新的後台資料而不斷髮生變化。由於伺服器必鬚根據多個使用者與應用程式的互動來產生每個頁面,因此我們實際上無法兩次產生相同的文檔。因此,網頁瀏覽器或Proxy 伺服器無法快取服務器資源。

有幾種解決方案可以用來處理資源無法緩衝的問題。一種就是建立細粒度的資源在伺服器端的緩衝,這樣伺服器就可以通過預先組合好的部分來構建一個粗粒度的頁面,而不是通過基本元素(HTML 和資料)從頭開始一步步地構建這種頁面了。但是問題依然存在:每個請求都會導致大量的伺服器處理,這會損害系統的延展性,還可能會對使用者感受到的響應性造成負面影響。

無法提供可緩衝資源的另外一個結果是:動態程度相當高的 Web 應用程式必須顯式地禁止搜尋引擎和其他類型的 “機器人”作出請求,因為處理這類請求的成本都非常昂貴;而在符合 REST 準則的應用程式中,只需一次性地將某個資源提供給那一類 “機器人”,然後對它們的後續訪問發送一條簡單的 “Not-modified” 訊息即可。

不使用 Ajax 的用戶端的處理

隨著訪問 Web 應用程式的使用者越來越多,系統需要的資源也會逐漸增加。可以讓伺服器來處理這一切,但將需要容量更大的伺服器或叢集伺服器(伺服器端狀態在叢集環境中並不太適用)。但如果將處理分布到客戶機上,那麼每增加一名新使用者,您就相當於有了一台支援部分新負載的新電腦。如果將工作階段狀態分布到客戶機上,那麼就有了一個無狀態的伺服器 —— 這是可伸縮 Web 應用程式中令人滿意的一項特性。這看上去應該是種非常明智的做法,那麼為什麼不按這種方法設計所有融入式 Web 應用程式呢?在 Ajax 出現之前,答案非常簡單:每次使用者訪問一個新的 Web 頁面時,應用程式狀態時就會被銷毀。

每次訪問一個 Web 頁面時,都要下載一個或一組包含內容的檔案(包含在結構化資訊中的資料,例如表和列表),以及影響內容外觀的樣式(例如,紅色文本)。在 網頁瀏覽器中,這些資訊都是作為文檔對象的抽象集來查看的。下面的列表為例:

  • Ford
  • BMW
  • Toyota

瀏覽器會認為這個 HTML 是一個 “無序清單” 對象,其中包含了 3 個列表元素;每個列表元素都包含文本。整個文檔可視為一個複雜的相關對象樹。當我們從一個頁面瀏覽到另外一個頁面時,瀏覽器就會銷毀當前頁面的對象樹,並為下一頁建立一個新的對象樹。

但是為什麼要在一個負載過重的伺服器上集中這麼多的資源消耗呢?從理論上來說,我們什麼時候可以將處理和記憶體需求分布到客戶機呢?簡單的答案是給定傳統 網頁瀏覽器約束,這是不可行的(請參看 不使用 Ajax 的用戶端處理)。但是 Ajax 架構風格使開發人員可以將處理和狀態需求分布到客戶機。請繼續閱讀,學習為什麼選擇使用 Ajax 風格的融入式應用程式可以繼續遵循 REST 準則,並充分利用它的優勢。

Ajax 和 REST

正如我們前面看到的一樣,傳統的伺服器端 Web 應用程式將資料的標識和伺服器上的動態資料元素合并在了一起,並將所構成的完整 HTML 文檔返回給瀏覽器。Ajax 應用程式在其主要 UI 和瀏覽器中的主要邏輯方面有所不同;基於瀏覽器的應用程式代碼可以在必要時擷取新的伺服器資料,並將這些資料織入當前頁面(請參看 參考資料 中 Jesse James Garrett 有關 Ajax 的啟蒙文章)。呈現和資料繫結的位置看起來可能是一個實現細節,但是這種區別會導致完全不同的架構風格。

利用有狀態 Web 客戶機的優點

人們通常將 Ajax 應用程式描述成無需在每次點擊時徹底地重新整理整頁的 Web 頁面。儘管這個描述非常確切,但是根本的動機在於徹底重新整理整頁會令使用者不耐煩,從而無法獲得愉快、融入式的使用者體驗。從架構的角度來看,整個頁面全部重新整理的設計甚至非常危險,這種設計使您無法選擇在客戶機儲存應用程式狀態,這可能會導致妨礙應用程式充分利用 Web 最強大的架構設計點的設計決策。

Ajax 讓我們不需要進行完全重新整理就可以與伺服器進行互動,這一事實使有狀態客戶機再次成為可用選擇。這一點對於動態融入式 Web 應用程式架構的可能性有深遠的影響:由於應用程式資源和資料資源的綁定轉換到了用戶端,因此這些應用程式都可以享受這兩個世界中最好的東西 —— 融入式 Web 應用程式中動態、個人化的使用者體驗,以及遵守 REST 準則的應用程式中簡單、可伸縮的架構。

緩衝 Ajax 引擎

設想一下,將 Amazon.com 徹底重新實現為一個 Ajax 應用程式 —— 一個 Web 頁面可以從伺服器上動態擷取所有的資料。(出於商業原因,Amazon 可能並不希望這樣做,不過那是其他文章討論的話題了。)由於現在有很多 UI 和應用程式邏輯都可以在客戶機而不是在伺服器上運行,根據 Garrett 的說法,最初載入頁面時需要下載 Amazon 的 Ajax “引擎”。這個引擎包含大量應用程式邏輯(以 JavaScript 代碼實現),另外還有此後將使用從伺服器上非同步擷取的資料填充的 使用者介面架構(見圖 4):

圖 4. 融入式 Ajax 應用程式

Ajax 引擎一個有趣的特徵就是:儘管它包含了很多應用程式邏輯和表示架構元素,但是如果經過恰當的設計,它可以不包含任何業務資料或個人化內容。應用程式和表示都凍結在部署時。在典型的 Web 環境中,應用程式資源可能 6 個月才會變更一次。這意味著負責隔離應用程式資源和資料資源的 Ajax 引擎是高度可快取的。

Dojo Toolkit 就是一個很好的例子(請參看 參考資料)。Dojo 提供了構建時工具來建立一個包含所有應用程式邏輯、表示和風格的壓縮 JavaScript 檔案。由於它終究只是一個檔案,因此 網頁瀏覽器可以對其進行緩衝,這意味著我們第二次訪問啟用 Dojo 的 Web 應用程式時,很可能就會從瀏覽器緩衝中載入 Ajax,而不是從伺服器上載入它。我們可以將這種情況與高度融入化的伺服器端 Web 應用程式進行一下對比,後者每次請求都會導致大量的伺服器處理,因為瀏覽器和網路中介不能對緩衝不斷變化的資源。

由於 Ajax 應用程式引擎只是一個檔案,因此它也是可以使用代理緩衝的。在大型的企業內部網中,只要有一名員工曾經下載過某個特定版本的應用程式的 Ajax 引擎,其他任何人都可以從內部網網關上上擷取一個緩衝過的拷貝。

因此對於應用程式資源來說,經過良好定義的 Ajax 應用程式引擎符合 REST 準則,與伺服器端 Web 應用程式相比,它具有顯著的延展性優勢。

緩衝 Ajax 資料

使用者瀏覽一個 Ajax Web 網站,載入 Ajax 應用程式引擎,最好是從瀏覽器緩衝中載入的,否則就從本地Proxy 伺服器載入。那麼對於業務資料來說情況如何呢?由於應用程式邏輯和狀態都在瀏覽器上駐留並執行,因此應用程式與伺服器的互動就與傳統 Web 應用程式的方式有很大的不同。不需要擷取混合的內容頁面,只需要擷取業務資料即可。

現在回到 Amazon.com 的例子上來,假設我們點擊了一個連結,要查看有關設計模式的一本書籍。在 Amazon.com 目前的應用程式中,連結點擊操作會發送很多標識所請求的資源的資訊。它還會發送很多工作階段狀態資訊,這讓伺服器可以建立一個新頁面,其中可以包括之前的狀態(例如最近查看的內容)、個人化資訊(例如您在 1999 年購買的書籍)以及實際的業務資源本身。應用程式是動態且高度個人化的 —— 但是卻不能緩衝,也無法伸縮(正如 Amazon 所示範的一樣,這些架構問題都可以通過投入大量資金構建基礎設施來克服)。現在我們考慮一下這個操作在(假想的)Ajax 版本的應用程式中的情況。對於 “最近查看的內容” 並不需要進行處理。當我們點擊某個連結時,這些在頁面上已經存在的資訊並不會消失。有兩個請求很可能會與設計模式的書籍有關:

  • /Books/0201633612(其中 0201633612 是設計模式書的 ISBN 號)
  • /PurchaseHistory/0201633612/bhiggins@us.ibm.com

第一個假定的請求會返回有關書籍的資訊(作者、標題、簡介等);其中並沒有包含特定於使用者的資料。特定於使用者的資料意味著當更多使用者請求相同的資源時,很可能會從 Internet 上的中間節點上來檢索緩衝版本,而不是從原始伺服器上檢索這些資源。這種特性會降低伺服器和總體網路負載。另外一方面,第二個請求包含了特定於使用者的資訊(Bill Higgins 的購買該書的記錄)。由於這些資料包括一些個人化資訊,因此只有一名使用者需要從這個 URI 中擷取並快取資料。儘管這種個人化資料並沒有非個人化資料的可伸縮特性,但是重要的問題是這些資訊都是直接從 URL 中擷取的,因此都具有這樣的正面特徵:它們都不會妨礙其他可快取的應用程式和資料資源的緩衝

Ajax 和健壯性

Ajax 架構風格的另外一個優點是它可以輕鬆處理伺服器的故障。正如我們前面介紹的一樣,具有融入式使用者體驗的伺服器端 Web 應用程式通常會在伺服器上儲存大量的使用者工作階段狀態。如果伺服器發生了故障,工作階段狀態就丟失了,那麼使用者就會體驗到非常奇怪的瀏覽器行為(“為什麼我又回到首頁上來了?我的購物車中的東西都到哪裡去了?”)。在採用有狀態客戶機和無狀態服務的 Ajax 應用程式中,伺服器崩潰/重新啟動對於使用者來說都是完全透明的,因為伺服器崩潰不會影響工作階段狀態,這些都儲存在使用者的瀏覽器中;無狀態服務的行為是等冪的,可以由使用者請求的內容來單獨確定。

 



回頁首

 

承諾和問題

對於我們稱為融入式 Web 應用程式的那些 Web 應用程式來說,設計良好的 Ajax/REST 應用程式在使用者體驗、響應性和延展性方面都遠遠超過傳統的伺服器端 Web 應用程式。然而,一種架構風格的運行時特徵對於軟體項目和 Web 應用程式來說並非是決定成功的惟一因素。在建立 Ajax/REST 應用程式時有一些非常困難的非運行時問題,包括大規模 JavaScript 開發、文化問題和打包問題。我們將在另外一篇文章中討論有關文化的問題,其他內容留待我那些研究 Ajax 的同僚們去處理。

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.