面向資源的架構:REST的另一面

chuanzhongdu1發表於2011-07-22

作一個假設,假如把你送回全球資訊網出現以前。想象一下你如何去跟當時那些毫無準備的人們解釋那即將發生的重大變化。結果很可能是他們根本無法深入地理解全球資訊網的出現將會對他們生活的每個方面產生的影響。在回顧中,那種感覺就像一場突如其來的海嘯,永遠地改變了我們身邊的景象。而現實可就樸實得多了,我們現在所經歷的這些結果都是由一系列深思熟慮的技術選擇及它們之間的相互作用所造成的。


這一浪潮同樣歷經了多年的努力,並且同樣是由認真思索後所選擇的特定技術來驅動的。通過這些選擇的組合,可以解決因不斷髮生的技術變化、業務膨脹、新的及變更的資料來源、以及那些普遍存在的既昂貴而又易出故障的花了大價錢卻又不能交付相應價值的專案所帶來的問題。Web服務與面向服務的架構原本被看做是解決問題的一個答案,然後他們那優雅的願景卻永久地因為拙劣的技術解決方案而染上了汙點。而現在,稍作停頓,想一想把你自己放在那些曾經對Web保有懷疑態度的人們所處的位置,正要被別人開化。除非你保持足夠的警覺,不然你又會再一次毫無準備地面對新一輪經濟上、社會化、技術化、以及組織形式上的衝擊!儘管這種改變令人感覺發生在一夜之間,實際的情況是它們都經歷了經年的積蓄,而現在才產生了有形的結果。這種新的浪潮就是Web的發展已經逐漸超越了文件,而成為了資料的網路,包括個人的和私有的。我們不再關注資訊的載體,而轉向關注資訊本身以及它們如何聯絡。

可喜的是我們並非是從零開始。我們是建立在原有的資料Web的技術的發展之上的。我們可以將資料庫、軟體包、服務以及其它的內容源打包成新的抽象集合,從而幫助我們擺脫過去那種單調乏味的工作。我們將公共的資料Web與我們自己的私有資料整合起來。不斷漸進地採用這些技術將會收穫新的能力,而這些能力又能釋放出更多的能力。

本文是這系列文章中的第一篇,該系列突出了面向資訊系統的演化、告訴我們位於什麼位置,並給出了我們發展的路線圖。不管從表面上看是怎樣,這些選擇不是隨機或神祕地做出的決定,而是基於學術與應用工程的長期傳統而作出的根本抉擇。

我們重新回到表象化狀態轉移(REST)架構風格。它經常被引用,可更多的是被誤解,這一構建網路軟體系統的方式允許我們將文件,資料和麵向資訊的服務融合成一個豐富的具名資源的邏輯性生態系統。從這裡開始,我們將引入語義網的願景,並領略由靈活與擴充套件兼備的資料模型和查詢能力所代表的語義網的核心技術。我們將看到如何將關係型資料、來自文件的內容、電子表格、RSS feed等等包含進一個由可重用內容組織的富Web。

在展示了這些基礎之後,我們將會去領略各種構建於這些技術之上的成功專案,並回來重新恢復Web服務技術所支援的曾對我們許諾過願景。我們將會描述一個流程,我們可以以此達成一個資訊系統統一理論;它不僅能處理,並且將擁抱那些過去痛苦而又棘手的技術性和社會性變更。

關於語義網的炒作已經太多了,但同時也有一股穩定的分支在默默的通向成功。這一系列文章對新的以及已熟知的領域都會作一個指引。但我們將會從你未曾看到過的更深的層次將這些技術聯接起來。我們將會強調企業,政府組織以及標準實體所發生的事件和行動,以表明我們是正處於這樣的程式中,並且這將改變一切。我們將展現通過微妙的視角轉換和施行促進變更的標準將會對你的系統實現帶來多麼大的變化。

第一步,是為基礎設施的所有方面採用公共的命名模式。一個只關注服務的架構往往忽略了流經系統的資料流。到頭來,我們的組織第一個關注的是資訊。REST和Web架構將這一優先順序擺在了前面,併為我們後面的討論做好了鋪墊。

Rest的其他方面

在與複雜性的鬥爭中,人們討論表象化狀態轉移(REST)已成為了一種時尚。這場戰鬥的敵人,據某些人的觀點,是SOAP以及圍繞它的Web服務技術棧。這種敵我的修辭給論點帶來了激情,但卻很難產出有意義的對話,所以人們對於其蘊含的訊息以及其重要性仍然感到困惑。REST的目標不是代替SOAP;而是構建更好的系統。

REST甚至不是SOAP的直接替代。它並非什麼方便的技術,或者所謂的通過URL呼叫Web服務的簡單解決方案。對於資訊資源的管理與呼叫隨意性的行為本就不是同一回事,這種混淆使得人們構建出的所謂"RESTful"解決方案,既非RESTful,也不是好的解決方案。

REST的益處既得自於它的限制又得自於它的靈活性。如果你讀過Roy Fielding博士的論文(你值得一讀),你會明白其意圖是描述特定的架構性約束是如何組合起來而產生了一系列我們在網路軟體系統裡所期待的屬性。採用統一的介面,赫赫有名的統一資源定位器(URL)對REST的定義有貢獻,但仍不足以定義它。同樣的,僅僅是通過URL來暴露隨意性的服務介面,也無法產出我們所看到的暴露Web同樣成功的益處。它要花費更豐富的一系列互動與系統劃分才能得到完整的結果。

大多數人的理解是,REST牽涉到使用幾個動詞通過URL來請求和提供資訊資源的應用資訊。你對URL發起GET請求來抽取資訊,你通過POST和PUT來建立和更新,而DELETE請求用於移除資訊。

這一總結並沒有錯,但它只是其中很小的一部分。不幸地是,它省略掉的部分所產生的自由度往往使得人們作出錯誤的決定。在這種鴻溝中,人們脫離動詞來建立URL,這就消除了給事物命名所帶來的好處。 他們認為REST僅僅關心CRUD操作。他們會建立一些神奇的不相關的URL,你必須事先知道如何解析,因此喪失了超文字引擎的可發現能力。而最不可原諒的,就是建立的這些URL單獨與特定的資料格式關聯起來,過早地對客戶端的資訊狀況作了決定。

理解REST整體的含義有助於你避免這些問題;它能幫助你開發強勁的、靈活的、可伸縮的系統。但這同時也是對於資訊以及它是如何被使用的一種全新理解的一個起點。在這樣的Web架構基礎之上,應用語義網的其它技術就會產生出前所未有的力量,而對我們作為個人,作為政府,組織等等如何相互進行互動產生影響。這也解釋了我們為什麼一來就深入到REST的那些不怎麼為人所知和被人談及的部分。這些部分的含義包括以下主題:

  • URL作為識別符號
  • 自由的形式
  • 邏輯連線的延遲繫結系統
  • 超文字作為狀態轉移的引擎(HATEOS)

URL作為識別符號

我們已經建立了這樣一種前提,大多數人都知道URL和REST。比較明顯的一點是人們都知道把URL用作呼叫服務,但人們對於把URL作為資訊的命名這種巨集觀的概念還不是很熟知。名字是我們用來標識人員、地點、物體和概念的。如果我們沒有這種標識的能力,我們就沒有表示的能力。每天想想Abbott和Costello的臭名昭著的詼諧劇“誰在一壘”。有了命名我們就可以消除歧義,並在一定的上下文範圍內明確地標識我們所關心的東西。有了命名和公共的上下文我們就能在這一範圍內明確的對命名的事物進行參照。

統一資源識別符號(URI)是父級模式。它是用於編碼其它模式的一種方法,取決於你是否想要包含進它們的解析資訊。圖書管理員和其它的長久資料管理員都喜愛不會改變的名字。統一資源名稱(URN)是不包含定位資訊的URI;它只包含名字。好處是這些名字不會失效。而壞處是這些名字沒有解析過程。一個URN的例子是書籍的ISBN號:

urn:isbn:0307346617

為了查詢關於這本書的更多資訊,你需要找到一個可以根據ISBN號來查詢資訊的服務。

如果我們的系統和資訊的上下文不會有改變的話,我們也許會始終把解析資訊包含在資源名稱裡以便解析。但只要是遇到過失效的連線的人都能理解對於一些重要的事物我們會想要長期有效的名字。回顧我們使用URL的歷史,我們做了不少錯事,比如:

http://someserver.com/cgi-bin/foo/bar.pl
http://someserver.com/ActionServlet?blah=blah
http://someserver.com/foo/bar.php

這些URL的問題在於,用於產生結果的技術與資訊的消費者毫無關係。這樣建立URL沒有任何站得住腳的理由。應該關注的是資訊,而不是技術。實現技術總是在不斷更新。如果你摒棄了他們,舉個例子,任何一個連結到基於Perl,Servlet或PHP的URL就會失效。接下來的文章中我們會討論到處理這一問題的一些基礎設施,而現在,我們將只關注對於命名我們的資訊資源如何作出明智的選擇。

儘管脆弱,但URL模式確實為我們提供了在全域性的上下文裡消除資訊引用歧義的能力。

http://company1.com/customer/123456

就能很好的區別於

http://company2.com/customer/123456

而像“123456”這樣的非上下文的識別符號則不能。

將這一理念根植於更廣泛的資訊系統框架,你可以將URL想象成不特定於任何具體資料庫的主鍵。我們可以在各種不同的資料庫,文件,應用中通過URL來引用一個條目,並且可以確定我們引用的是同一個事物,因為在整個全域性的上下文中它有一個唯一確定的名字。在後續的討論中我們將使用這一特性來描述RESTful系統並將其與其它內容和後設資料連線起來。

URL另一個值得討論的方面就是它們的統一適用性。我們有著一個公共的命名模式可以去識別:

  • 文件(報告,部落格,公告)
  • 資料(成果,例項資訊,後設資料)
  • 服務(REST!)
  • 概念(人員,組織,領域特定術語)

我們不需要創造一種另外的機制來參照每個不同類別的物件。某些特定準則的嚴謹的應用允許我們模糊這些物件的區別,這就把我們領到了關於URL的最後一點。這些名字不僅對於參照我們所關心的資訊是有用的,而接收這些引用的系統也可以輕易的請求它們。URL中的“L”(定位器)給予了我們就算不了解它的其它任何情況,也能解析它的能力。對於我們命名的物件,通常我們都可以對其呼叫同樣的基礎操作。對於以URL的形式所表示的文件,資料,或者是產生該資料的服務,甚至是一個抽象的,不可通過網路訪問的概念,發起一個GET請求工作原理從根本上來說是相同的。對於我們被授權操作的這些事物,我們也可以以同樣的方式來建立,修改或者是刪除它們。

自由的形式

我們對於Web的經驗就資訊的形態來說仍顯被動。當我們點選連結時,我們期望內容以某種特定的形式返回,通常是HTML。對於許多型別的資訊來說這是很好的,但架構對於更多的會話風格提供了豐富的支援,使得客戶端可以用它們更青睞的形式請求資訊。

要理解它的作用所在,可以考慮一個公司的銷售報表。可以想象得到對於管理層、銷售人員、其它的員工、客戶和投資者而言這將是衡量公司業務表現的一個有效的指標。這種報告的名字可以在URL中包含進年份和季度:

http://company1.com/report/sales/2009/qtr/3

我們可以將它與3月份的銷售報表作個對比:

http://company1.com/report/sales/2009/month/3

兩者都是很好的有邏輯內涵的名字,而且不會因時間而失效。人們可以輕易的在瀏覽器輸入這樣一個URL然後就能以HTML的形式得到他們尋找的資訊,這種願景非常誘人。這個報表可以被新增到書籤,通過電郵傳送,被連結到,我們所鍾愛的Web的方方面面。

題在於,資訊鎖定在表現形式中(除非我們在本系列稍後引入GRDDL和RDFa這樣的技術後!)。我們習慣於從頁面獲取內容,但卻放棄了而只獲取摘要。隨著頁面的排列改變了,我們的指令碼也就失效了。

如果你曾是公司的一名程式設計人員,而你想要直接獲取資訊的話,你可能會想要通過XML去請求它。你可以得到原始的結構化資料,你可通過模式來驗證。HTTP和REST讓這變得易如反掌,只要伺服器知道該如何響應。通過在請求中傳遞一個“Accept:application/xml”的頭部資訊,你可以表明你請求的是(或你的需求是)XML。成功的話,你將會得到一個位元組流的MIME型別,以表明你的請求被接受了。如果失敗,伺服器將通過一個406錯誤表示無法幫助你。在這種情況下,你也許會想要聯絡負責該資訊的部門並要求他們加入你所需要的支援;他們既能做到而又不會影響現有的客戶。 如果你是業務分析師,你會覺得XML過於粗糙而有點棘手,你可能想要返回電子表格,這一格式將非常適宜於融入你現有的工作流,工具和流程。

關鍵點在於該報表的邏輯名字在它被請求的時候可以輕易的轉換成多種不同的格式。而執行能夠接受這些各種各樣修改後的格式的系統也是同樣的容易。客戶不能看到資訊是如何被儲存的真實情況,他們只需要知道它能工作就行。而這樣的自由度竟未被構建RESTful的人員加以完全的利用。當他們搭建一個服務並決定僅僅返回XML的時候,他們忽略了REST原本可以為組織提供的潛在價值。

許多開發者出於不瞭解內容協商,或者覺得很難在瀏覽器裡對它進行測試,他們就對不同的格式定義了不同的URL:

http://company1.com/report/sales/2009/qtr/3/report.html
http://company1.com/report/sales/2009/qtr/3/report.xml
http://company1.com/report/sales/2009/qtr/3/report.xls

一旦你越過的特定用途的約束,這樣的開發者捷徑反而會變成一種侷限。本質上講,我們現在有三種資訊資源,沒有一個可以以其它的形式來展示。這不僅在全域性上下文中建立了身份標識的分支,它同時還過早的向客戶端承諾了特定的形式。如果你將一個對URL的引用作為工作流或者是編配的一部分,那你就掠奪了上游客戶自由選擇資料格式的權益。

有幾種不使用瀏覽器測試正確的RESTful服務的方法,例如:

curl -H "Accept: application/xml" -O http://company1.com/report/sales/2009/qtr/3

使用流行的curl程式,任意一個合理的HTTP客戶端都會提供類似的功能。

支援可協商資料格式的富生態系統所帶到的益處也許並不是立竿見影的,但一旦你投入進去,你就會發現它是邁向一個生命長久而靈活的系統的關鍵,它有益於客戶,而不是開發者。

邏輯上連線的延遲繫結系統

一旦你為資訊資源作出了良好的邏輯性的命名,你就會發現因這樣的決定而帶來的附加的好處。命名的引用可以安全而高效地作為結果傳遞回去,而不用返回實際的資料。這對於大量而敏感的資料有著極大的意義,但同時這也意味著可能出現技術和架構的遷移。

出於指標在C和C++語言的作用同樣的原因,URL作為資料的引用而傳遞給資訊的訊息者是一種更為緊湊和高效的方式。諸如金融交易,衛星照片這樣的大資料集可以在工作流中引用而不必要求所有的參與者都去承擔處理大容量內容的壓力。

何接觸到實際資料的編配都必須考慮到將其傳遞給其它系統可能帶來的安全性影響。很快就會發現要提供哪些人在流程的每個步驟被允許做什麼的精確資訊是難以維持的。如果一個引用一步一步地被傳遞,那就該是資訊源本身來保障訪問許可權。有些步驟不要求訪問敏感的資訊,因此在它們解析引用的時候就可以排除它們接收資訊。

這意味著延遲繫結解析可以在整個請求的上下文中發揮作用。使用某一應用訪問一個資源的特定使用者也許有出於業務需要檢視敏感資料的需求。而同一個人使用另一應用卻不一定有業務上的正當理由來訪問同樣的資料。一個RESTful服務可以檢查會話標誌並且可以宣告式的保證這一訪問策略。這一層次上的明確性是需要的,以此才能防範內部欺騙,它通常是處理敏感內容系統的最大的威脅。這樣一個系統的細節應當是特定實現的,並且與命名流程和解析邏輯命名的內容很大程度上是正交的。

依賴於邏輯關係能夠保護客戶不受實現變更的影響。當流行的網站從一種技術遷移到另一種技術,它們都能夠成功地向使用者隱藏這些變更。RESTful也是這麼做的。這讓我們可以自由地將遺留系統打包成邏輯介面並得以保留,直到因業務發展而投入新的實現。當出現這種情況的時候,使用者也可以受到庇護而不受影響。

為了調停技術的變更,RESTful系統允許你使用Postel法則的一個變形:保守的給予,自由的接受。你可以對於你接受和返回的內容保持嚴格的驗證。然而,如果你有一個現有的客戶群向你提供某種給定形式的內容,你可以允許其它的客戶提供不同的形式,不同的模式,而不影響現有的客戶。與終端保持緊密關聯合約的系統不可能提供這樣的自由度,這將使他們更脆弱並且會很快瓦解。

超文字作為狀態轉移的引擎(HATEOS)

當系統遇到資訊資源的引用時,很多人認為應當需要某種描述語言來指示什麼是的可能或者應該做的。實際的情況是一個經過嚴密思考後的RESTful系統通常不需要這一概念。這對於SOAP開發者而言難以接受,但這是與架構風格的約束相關的。因為我們將資訊資源看作是通過統一介面(URL)來操作的物件,並且將我們的行為侷限著一個很小的動詞集合裡,因此確實沒必要對服務進行描述。

如果你在這一點上有所疑惑,很可能是在架構風格的品位上你仍在操作資源與呼叫隨意性行為之間產生了猶豫。REST動作對應用一個資訊資源提供了全套的操作。當然,你需要知道返回的是什麼資訊你才能知道如何處理它,但這是MIME所關心的問題。儘管重用已知的型別(application/xml,image/png,等等)更為人所接受,但很多開發者並不明白如果需要的話他們可以建立自己的應用特定的資料型別。

在本系列文章的軌跡中,我們將討論使用富後設資料查詢和繫結隨意性資源的問題。現在,我們只需要簡單的記住Roy所強調的“超文字作為狀態轉移引擎”的重要性(又被REST粉絲簡稱為“HATEOS”)。這恐怕是論文中引起最多誤解的部分,要理解它的全部內涵,我們得重新過一遍Web是如何工作的。

你在瀏覽器中輸入URL,它會向該資源發起一個HTTP GET請求。不變的是,伺服器將響應一個位元組流,一個響應程式碼(通常成功返回200),以及一個MIME型別以表示響應的是HTML。瀏覽器將決定它知道如何處理這一型別,並將結果解析成某種型別的文件模型。在這一模型中,可以找到對其它資源的引用:連結、圖片、指令碼、樣式表等等。它會區別對待每一項,但都是在解析原始資源的過程中去發現它們的。這裡不存在服務描述,瀏覽器作為客戶端,直接就知道如何分析結果。

RESTful服務也應當使用同樣的機制。URL本身不應當是“魔力的”。客戶端不應當被要求瞭解如何去分析一個URL或是對於一個層次相對另一層次而言意味著什麼有詳細的認識。RESTful客戶端只需要取回資源,調查返回的MIME型別並分析結果。這樣一來,客戶端就知道如何分析返回的型別了。

舉例來說,一個客戶端可能會接收一個我們上面所描述的用於報表服務的主RESTful服務的引用:

http://company1.com/report/

如果是通過瀏覽器發出的請求,可能會返回一個包含如下引用的HTML文件:

http://company1.com/report/sales

使用者可以點選進入並找到可瀏覽的年份列表。要說明的是瀏覽器對於URL的結構並沒有特別的認知,但它知道如何分析結果並以使用者可以瀏覽的結果返回內容。

對於其它的MIME型別道理也是一樣,比如以XML的格式請求2009年的季度報表:

http://company1.com/reports/sales/2009/qtr

可能得到:

<reports>
    <description>2009 Quarterly Reports</description>
    <report name="First Quarter" src="http://company1.com/reports/sales/2009/qtr/1"/>
    <report name="Second Quarter" src="http://company1.com/reports/sales/2009/qtr/2"/>
    <report name="Third Quarter" src="http://company1.com/reports/sales/2009/qtr/3"/>    
</reports>

你可以將URL想成是貫穿資訊空間的向量。每一個層次都進一步的將你指向最終的資源。不同的路徑可能產生同樣的結果。客戶端需要知道如何分析這些結果,但通過對響應給出可識別的型別,我們可以觸發合適的分析器。這一結構可通過爬蟲降序的從引用來抓取,或者以某種介面展現給使用者瀏覽。一個RESTful介面成為了客戶端通過基於已知來請求資訊的方式。它們以一個已知或者已發現的點作為開始,就像你瀏覽web一樣來瀏覽資訊。

這就是HATEOS所指代的。應用的狀態在超文字響應中被轉移和發現。就像瀏覽器需要知道HTML、圖片、聲音檔案等等一樣,一個RESTful客戶端也需要知道如何分析解析資源引用的結果。然而,整個過程是簡單、受約束、可伸縮並且靈活的——這正是我們所期望的網路軟體系統的屬性。

許多人搭建的"RESTful"系統都要求客戶端事先知道URL的每一層次的意義。如果服務端將資訊重組了,這些系統的客戶端就會崩潰。真正體現了HATEOS的客戶端與它們所通訊的伺服器之間才更加能做到鬆耦合。

展望

我們每天掙扎於解決由快速變更的領域、技術、客戶需求以及行動知識等等方面引出的問題。我們花費了太多時間來編寫軟體,將我們所學到的與我們所已知的聯絡起來。物件與資料庫沒能夠跟上我們所經歷的變革。我們需要找到新的方式來看待我們所產生和消費的資訊,比過去的解決方案更為擴充套件並且更加健壯。我們需要技術來幫助我們達成一致。我們不需要先達成了公共模型形式的一致才來使用我們的技術。

在這篇文章中,我們作了該系列的開篇介紹,並且開始探討了REST與Web技術如何作為新的面向資訊架構的基礎。我們建立起了能夠讓我們統一引用各種內容,服務與文件的命名模式。客戶端可以利用這樣的自由度以他們想要的形式來協商資訊。當他們解析引用的時候,他們可以發現通過新的關係聯絡起來的新內容。

這一架構風格和技術與相關的語義網技術結合起來,可以漂亮地建立強大的、可伸縮的和靈活的軟體系統。它們建立資料Web的能力對我們的生活將產生的影響就像Web之前所產生的那樣。這將會是一場資訊系統的革命,我們的許多認知都將有很大程度上的改變。它不僅能降低資料整合的成本,還會使得我們只能進行想象的新型業務能力成為可能。

我們正在進入一個資訊的新世界,資訊可以被連線起來並使用,而不管它是被包含在文件內,資料庫裡,或者作為RESTful服務的結果而返回。我們將能夠發現內容並將其連線到我們所已知的部分。我們可以將現在隱藏在資料庫,電子表格,報表或者其它倉筒的資料暴露出來。我們不僅能獲得訪問這些資訊的許可權,還能夠以我們想要的方式消費這些資料。

這是語義網的一個主要的,小小的目標。達到這個目標,而我們現在也有能力做到,將會是一切改變的開始。

檢視英文原文Resource-Oriented Architecture: The Rest of REST

中文原文:http://www.infoq.com/cn/articles/roa-rest-of-rest

相關文章