|
任何概念從產(chǎn)生到付諸實(shí)施似乎都要經(jīng)歷一個(gè)同樣冗長(zhǎng)的過程,從被提出,誤解,詮釋,再認(rèn)識(shí),到應(yīng)用,好像沒有幾個(gè)技術(shù)觀點(diǎn)能夠跳過這些,現(xiàn)在的RESTful架構(gòu)似乎也正處在這個(gè)過程的中段。互聯(lián)網(wǎng)上關(guān)于REST的介紹性文章可謂鋪天蓋地,園子里的帖子也有不少,但是其中大多數(shù)都是一個(gè)對(duì)REST這一概念的精辟概述,比較流行的樣式是一句話總結(jié)或?qū)⑵涮匦粤斜恚@樣的總結(jié)對(duì)于讀者來說的確提供了較大的便利,它們?nèi)菀妆蝗擞涀。驳拇_反映了從最終使用者角度來看REST最為顯著的幾個(gè)特性。但是它們同時(shí)也很容易讓讀者覺得了解了這些就幾乎了解了REST的全部,而不會(huì)繼續(xù)探究細(xì)節(jié),也許這就導(dǎo)致了許多朋友對(duì)REST理解較為片面的原因吧。比如我看到有些朋友認(rèn)為操作HTTP原語(yǔ)就是REST,有些人認(rèn)為只要在URL上花心思了就是REST,其實(shí)他們的看法都表現(xiàn)了基于HTTP和URL的REST架構(gòu)風(fēng)格在實(shí)現(xiàn)層面的重要組成部分,但以其來定義REST本身未免過于草率。于是,我便有了寫這系列隨筆的想法。我并不是為了向大家介紹REST,而是想和大家分享下自己對(duì)這個(gè)架構(gòu)風(fēng)格的理解,如果能夠以此解答大家對(duì)于REST的一些困惑的話,那是我的榮幸。
相信任何關(guān)于REST的介紹性文章都會(huì)提到Roy T. Fielding博士在2000年發(fā)表的一篇論文,然而對(duì)這篇文章本身的關(guān)注度似乎比對(duì)它的引用要少的多。這篇論文本身并不僅僅是為提出REST而作的,而是介紹了一種以架構(gòu)風(fēng)格為指導(dǎo)的,針對(duì)網(wǎng)絡(luò)應(yīng)用架構(gòu)設(shè)計(jì)的方法論,而REST是被作為這種方法論的應(yīng)用推導(dǎo)出的一種適應(yīng)分布式超媒體系統(tǒng)的架構(gòu)風(fēng)格。文中作者將架構(gòu)風(fēng)格定義為:
一組協(xié)作的架構(gòu)約束,這些約束限制了架構(gòu)元素的角色和功能,以及在任何一個(gè)遵循該風(fēng)格的架構(gòu)中允許存在的元素之間的關(guān)系。
這里的“架構(gòu)約束”指的是對(duì)系統(tǒng)在運(yùn)行時(shí)表現(xiàn)出的某組屬性的需求。舉例來說,如果期望“系統(tǒng)具有可伸縮性”(系統(tǒng)屬性),那么在Web系統(tǒng)中對(duì)應(yīng)的架構(gòu)約束之一就可以是“在服務(wù)器上不保留會(huì)話狀態(tài)”。一般來說,基于Web的系統(tǒng)所關(guān)注的屬性主要有性能(Performance),可伸縮性(Scalability),可擴(kuò)展性(Extensibility),可移植性(Portability)和可靠性(Reliability)等,而把與其相對(duì)應(yīng)的相關(guān)約束進(jìn)行不同的組合便形成了各種架構(gòu)風(fēng)格。比如最為常見的Client-Server風(fēng)格,就是與可伸縮性和簡(jiǎn)單性等對(duì)應(yīng)的約束集合。Fielding博士在論文中對(duì)基于架構(gòu)風(fēng)格的分類有詳細(xì)論述,這里就不多做解釋了。基于前面對(duì)架構(gòu)風(fēng)格的定義,F(xiàn)ielding博士從識(shí)別互聯(lián)網(wǎng)應(yīng)用需求開始一步一步推導(dǎo)出了早期互聯(lián)網(wǎng)的架構(gòu)約束,并在此基礎(chǔ)上添加現(xiàn)代分布式超媒體系統(tǒng)所需要的屬性,從而獲得一個(gè)全新的架構(gòu)風(fēng)格,它表現(xiàn)了現(xiàn)代互聯(lián)網(wǎng)背后的運(yùn)轉(zhuǎn)模型,并滿足分布式超媒體系統(tǒng)提出的約束條件,這便是表述型狀態(tài)轉(zhuǎn)移(REpresentational State Transfer, REST)架構(gòu)風(fēng)格產(chǎn)生的過程。
這個(gè)過程意味著兩個(gè)事實(shí),首先,由于REST是為了獲得某種系統(tǒng)屬性的架構(gòu)約束集合,所以它不與任何具體實(shí)現(xiàn)相關(guān)聯(lián)。任何能夠滿足這組特定約束的實(shí)現(xiàn)都是可以被稱為REST式的架構(gòu)。雖然這一結(jié)論已經(jīng)有口皆碑,許多帖子或介紹性文章也都會(huì)有類似于“...REST首先只是一種架構(gòu)樣式,不是一種標(biāo)準(zhǔn)...”這樣的話,然而在我自己的學(xué)習(xí)過程中,這些簡(jiǎn)要的概述卻著實(shí)在理解上給我?guī)砹艘恍┞闊T?jīng)困擾過我的問題有“架構(gòu)樣式與標(biāo)準(zhǔn)有何區(qū)別”,“為什么REST算是一種架構(gòu)樣式”,“CS也算是一種架構(gòu)樣式那么怎樣區(qū)分將其與REST區(qū)分開來”等等,而在了解了REST的推導(dǎo)過程后這些問題便迎刃而解了。
另外,縱觀REST的推導(dǎo)過程,可以發(fā)現(xiàn)這一架構(gòu)風(fēng)格與互聯(lián)網(wǎng)緊密結(jié)合,我不是說在使用的技術(shù)上,而是在期望實(shí)現(xiàn)的架構(gòu)屬性方面,REST是基于互聯(lián)網(wǎng)所表現(xiàn)的屬性之上的。屬性代表著系統(tǒng)運(yùn)行時(shí)表現(xiàn)出的功能,也就是說REST風(fēng)格架構(gòu)的適用場(chǎng)合必然與互聯(lián)網(wǎng)密切相關(guān)。互聯(lián)網(wǎng)創(chuàng)始人Tim Berners Lee說過這樣的話:“The web is the universe of globally accessible information”,它點(diǎn)出了互聯(lián)網(wǎng)用于分享資源的屬性。那么我們能不能以此推論與之具有相似架構(gòu)約束的REST風(fēng)格也是面向資源的呢?答案是肯定的,而上面簡(jiǎn)短的推導(dǎo)過程也正是“REST是面向資源的(Resource-Oriented)”這一論述的理論依據(jù)。
資源作為REST架構(gòu)風(fēng)格的一個(gè)核心元素就其本身來說是沒有多大價(jià)值的,它們的價(jià)值來源于被人發(fā)現(xiàn)和使用,以及與其他資源間的交互。為了實(shí)現(xiàn)這一屬性,REST引入了稱為資源標(biāo)識(shí)符(Resource Identifier)的架構(gòu)元素,它們表現(xiàn)為一種查找和獲取資源的方法,使得資源具有可尋址性(addressability),在互聯(lián)網(wǎng)(作為REST架構(gòu)的一個(gè)實(shí)現(xiàn))中資源標(biāo)識(shí)符就是URL了。接下來被發(fā)現(xiàn)的資源必須通過一種方式被使用者認(rèn)識(shí)和使用,它們需要向客戶端“介紹”自己,有時(shí)候?yàn)榱擞峡蛻舳说目谖哆€需要以多種方式去“展現(xiàn)”自己,或展現(xiàn)“過去的自己”,這種展現(xiàn)在REST中便是資源的表述(Representation)。每一個(gè)資源都是其表述的來源(source),一個(gè)資源可以有多種類型的表述。舉例來說,“SNOOPY”這一資源可以被表述為一份描述一只狗的XML或是一幅漫畫,而無論它被描繪成哪種形式,其對(duì)于使用該資源的客戶來說都是長(zhǎng)篇漫畫Peanuts中的主角。從概念上來看,這和語(yǔ)義網(wǎng)(Semantic Web)的構(gòu)想是相似的,他們都有通過“一組正式的、被明確定義的詞匯,來記錄和描繪一個(gè)普遍認(rèn)知”的需求。前面提到資源可能會(huì)需要展現(xiàn)“過去的自己”,這可以被理解資源對(duì)其自身在某一個(gè)特定狀態(tài)(State)下的表述。舉例來說,上周我從圖書館借回來了一本名為《Everyday Italian》的書,由于發(fā)現(xiàn)書中部分內(nèi)容與我了解的不一致,我添加了一些批注。于是乎接下來所有這本書最新版本的請(qǐng)求都變成了由我添加過批注的這個(gè)版本(假設(shè)該書可供借閱的數(shù)量只有一本,而備份版本存于書庫(kù),需要提交申請(qǐng)),也就是說這個(gè)資源的狀態(tài)(Resource state)被“添加批注”這個(gè)動(dòng)作改變,而對(duì)該書最新版本的請(qǐng)求意味著對(duì)資源當(dāng)前狀態(tài)的表述的請(qǐng)求。我的批注惹惱了作者的一些FANS,于是有許多對(duì)備份版本的請(qǐng)求提交到了圖書館,類似于這樣“請(qǐng)給我該書2009年6月12日以前的最新版本”。圖書館管理員在收到這樣的請(qǐng)求后首先對(duì)我這樣的讀者發(fā)了句牢騷,然后根據(jù)索引號(hào)去書庫(kù)查找備份版本。在這個(gè)場(chǎng)景中,最終用戶得到的表述資源狀態(tài)發(fā)生了改變,從最新版本變?yōu)榱四骋惶囟〞r(shí)間的歷史版本,而資源本身并未改變(這里我將該書作為一個(gè)資源看待)。這里客戶端獲得的始終是資源的表述狀態(tài),對(duì)資源狀態(tài)的表述在請(qǐng)求響應(yīng)過程中從服務(wù)端被轉(zhuǎn)移(Transfer)至了客戶端,而在被轉(zhuǎn)移的狀態(tài)中又包含著將請(qǐng)求方引導(dǎo)至其他狀態(tài)的連接(Hyperlinks)。資源,表述,狀態(tài),轉(zhuǎn)移這幾個(gè)元素便成為了表述型狀態(tài)轉(zhuǎn)移(REpresentational State Transfer)這一架構(gòu)風(fēng)格的基本要素。
以上從架構(gòu)元素角度定義了REST風(fēng)格,而在資源的連接與交互方面,REST也提出了為實(shí)現(xiàn)系統(tǒng)可伸縮性、組件可替換性以及性能優(yōu)化等屬性的要求。這些約束中統(tǒng)一接口,無應(yīng)用狀態(tài)等是最為關(guān)鍵的幾點(diǎn),對(duì)他們的論述網(wǎng)絡(luò)上也比比皆是,比如發(fā)布于InfoQ上的A Brief Introduction to REST就很詳細(xì)地解釋了使用標(biāo)準(zhǔn)化方法與資源進(jìn)行交互和無狀態(tài)溝通的含義和原因,這里就不再贅述了。另外,我在過去的一篇帖子里也簡(jiǎn)單談了一些自己對(duì)無狀態(tài)這一概念的理解,有興趣的朋友可以參考一下,而對(duì)于基于HTTP和URL的REST中,統(tǒng)一接口和無應(yīng)用狀態(tài)的實(shí)際表現(xiàn)形式,例如對(duì)HTTP原語(yǔ)的使用等,我會(huì)在接下來的幾篇隨筆里與大家分享我的認(rèn)識(shí)。
REST源于互聯(lián)網(wǎng)也用于互聯(lián)網(wǎng),這也就意味著REST對(duì)其適用場(chǎng)合有著默認(rèn)的假設(shè)。由于REST將互聯(lián)網(wǎng)作為一個(gè)開放的發(fā)布媒體,而不是一個(gè)通信媒介,所以REST期望其應(yīng)用場(chǎng)景是一個(gè)為了通過網(wǎng)絡(luò)公開并分享某些資源的分布式超媒體系統(tǒng),這些資源可以是靜態(tài)文本或圖片,也可以是系統(tǒng)處理數(shù)據(jù)的能力。這也就意味著REST其實(shí)并不適用于一些業(yè)務(wù)邏輯復(fù)雜的企業(yè)應(yīng)用,此類應(yīng)用通常不希望任何與業(yè)務(wù)過程不相關(guān)的實(shí)體分享信息,而它們?cè)谄渌恍┓矫娴奶厥庖螅?a href=/yuedu/fuwuqi/ target=_blank class=infotextkey>服務(wù)器端對(duì)客戶端應(yīng)用狀態(tài)的保留和復(fù)雜的安全基礎(chǔ)設(shè)施等,都是與REST架構(gòu)風(fēng)格中某些約束相沖突或REST沒有涉及的。所以硬將REST風(fēng)格套用到這樣的企業(yè)應(yīng)用上,我覺得著實(shí)有點(diǎn)勉為其難。REST中的組件復(fù)合模式也同樣說明了這點(diǎn)。考慮下現(xiàn)在的一些信息門戶網(wǎng)站,許多信息的展現(xiàn)都是通過從多個(gè)來源獲取與相關(guān)的數(shù)據(jù)或功能來完善的,這也就是我們常說的mashup,而mashup便是REST所期望的信息(資源)復(fù)合模式。在這一形式中,資源與資源通過超鏈接連接成一個(gè)復(fù)合的表述,而不受某個(gè)高層工作流或既定業(yè)務(wù)流程的控制。與之相對(duì)的,企業(yè)應(yīng)用中的數(shù)據(jù)或功能通常是被作為某個(gè)業(yè)務(wù)流程中的一個(gè)組成部分被復(fù)合到一起的,這一流程指導(dǎo)著數(shù)據(jù)或功能的使用時(shí)機(jī)以及下一步的交互對(duì)象。在這個(gè)模式下服務(wù)器端維護(hù)狀態(tài)信息幾乎成為了必然,當(dāng)然可以將狀態(tài)信息存于客戶端,并通過將其包含于每個(gè)請(qǐng)求發(fā)送至服務(wù)端的方式來實(shí)現(xiàn)REST式的架構(gòu),但是這樣做沖銷了REST的簡(jiǎn)潔性的優(yōu)勢(shì),也可能增加網(wǎng)絡(luò)傳輸?shù)呢?fù)擔(dān)。
以上便是我對(duì)于REST架構(gòu)風(fēng)格的一些個(gè)人體會(huì),從解釋REST的推導(dǎo)過程到其適用場(chǎng)合的假設(shè),希望這些理論味道有點(diǎn)濃的文字能夠給大家?guī)硪恍┬⌒∈斋@。接下來的幾篇隨筆里我會(huì)主要和大家聊一下自己基于HTTP和URL的REST架構(gòu)中一些元素的理解,討論一些我在學(xué)習(xí)過程中看到的爭(zhēng)論,發(fā)表一下自己的看法。
閑話REST(二)對(duì)資源標(biāo)識(shí)符的一點(diǎn)認(rèn)識(shí)
it知識(shí)庫(kù):閑話REST(一),轉(zhuǎn)載需保留來源!
鄭重聲明:本文版權(quán)歸原作者所有,轉(zhuǎn)載文章僅為傳播更多信息之目的,如作者信息標(biāo)記有誤,請(qǐng)第一時(shí)間聯(lián)系我們修改或刪除,多謝。