當(dāng)我們談?wù)揜ESTful時,我們在談?wù)撌裁?/h2>

博客原文傳送門:當(dāng)我們談?wù)揜ESTful時,我們在談?wù)撌裁?/a>???

標(biāo)題好像有點噱頭,山人在此先檢討。去知乎了一下,發(fā)現(xiàn)這種句式叫做卡佛句式,好像村上春樹也用過,看來是雅俗共賞的。且回正文,最近Team要做一個Service,負(fù)責(zé)一些全局資源的管理,并為Internal的其他Services提供通用資源訪問接口。想著之前一直是用一些RPC-style的架構(gòu),不如來試試RESTful的吧。雖然關(guān)于什么才是真正的REST一直有很多爭論。

I- Web服務(wù)的架構(gòu)風(fēng)格

就像面向?qū)ο笈c面向過程編程模型一樣,Web Service應(yīng)用服務(wù)中也有兩種典型的架構(gòu)模式,Remote Procedure Call(即,RPC,還有一種類似的叫法Remote Method Invocation細(xì)微的不同之處在于,RPC通過調(diào)用遠(yuǎn)程的過程函數(shù),而RMI側(cè)重于通過獲取遠(yuǎn)程的對象引用,而通過對象引用調(diào)用其內(nèi)部的方法。)與REpresentational State Transfer(即REST)。通常RPC是Operation Oriented,其通過暴露內(nèi)部的操作接口,提供與之相應(yīng)的不同編程語言的Client API來實現(xiàn)客戶端與服務(wù)器的交互。通常與服務(wù)器的通信基于HTTP協(xié)議,但主要利用其作為一種傳輸媒介,把通訊的方法,信息以及狀態(tài)都封裝在HTTP協(xié)議的URI或是Body內(nèi)部。且大多使用GET或是POST等單一方法。而REST則是一種Resource Oriented架構(gòu),就像面向?qū)ο缶幊桃粯?,其把一個對象實體視為一種數(shù)據(jù)資源,針對每一種數(shù)據(jù)資源都會有相應(yīng)的Service Endpoint,其也用HTTP協(xié)議,但不同于RPC,REST充分利用了HTTP協(xié)議在WWW上取得的成功,直接視HTTP協(xié)議為一種應(yīng)用層協(xié)議,重用其各種HTTP方法,以及統(tǒng)一響應(yīng)碼定義,為全網(wǎng)范圍內(nèi)分布式系統(tǒng)通信提供了統(tǒng)一規(guī)范標(biāo)準(zhǔn)。

嚴(yán)格來說REST本身并不是一種具體架構(gòu),而是一種更高level的標(biāo)準(zhǔn)規(guī)范。初見于Roy Fielding的論文中,文中試圖提出一種針對分布式超媒體(Hypermedia)系統(tǒng)架構(gòu),具有豐富表達(dá)能力的應(yīng)用程序狀態(tài)轉(zhuǎn)換(即REST)Web應(yīng)用服務(wù)的軟件工程設(shè)計原則。以及依照這些原則下,規(guī)定客戶端與服務(wù)器交互時應(yīng)該遵守的一些限制。比如客戶端與服務(wù)器的交互需是無狀態(tài)的;為了提高Service性能而引入緩存機制;為了簡化整個系統(tǒng)架構(gòu),提高交互的可見性提出的Uniform Interface的限制等論文中主要有如下constrains:

。論文是在2000年寫的,開創(chuàng)性和預(yù)見性可想而知。而正是因為其不是具體的某個實現(xiàn)架構(gòu),也不是真正如RFC那樣的定義清晰的業(yè)界標(biāo)準(zhǔn)。這么多年來,對REST的解讀自然是仁者見仁智者見智了。

隨著近幾年RESTful Service越來越熱,幾乎每一個人在設(shè)計Web Service架構(gòu)時都聲稱自己是遵照REST原則來設(shè)計的。因而誕生了好多RESTful Service API。但其實大多數(shù)系統(tǒng)的設(shè)計都是不倫不類的RPC與REST混合體。正如Richardson在他的那本經(jīng)典的RESTful Web Services中所說,其實多數(shù)人設(shè)計的都是RESTful-RPC混合架構(gòu)模式。但既然我們的主要爭論點在RPC和REST這兩者身上,不妨通過特征比較法來看看二者的主要不同點。

II- RPC vs REST

RPC和REST都是基于HTTP協(xié)議的,我們不妨先看看他們使用HTTP請求的方式有什么不同。當(dāng)Client發(fā)起一個基本的HTTP請求,首先需要確定兩個內(nèi)容,即

HTTP Verb(Method)

URI(Resources Endpoint)

1- HTTP Verb

對于RPC而言,常用的HTTP方法只是POST和GET,尤其對于POST的使用比較依賴。且很多時候決定是使用GET還是POST的主要依據(jù)就是是否請求含有數(shù)據(jù)。而對于經(jīng)典的RPC架構(gòu)的產(chǎn)物,如XML-RPC或是SOAP-RPC,由于關(guān)于調(diào)用服務(wù)的所有信息,如操作類型,數(shù)據(jù)等都被封裝在XML或是SOAP協(xié)議體Envelope內(nèi),而該協(xié)議本身又只被作為HTTP協(xié)議體封裝傳輸。

XML RPC示例代碼

POST /RPC2 HTTP/1.0User-Agent: Frontier/5.1.2 (WinNT)Host: betty.userland.comContent-Type: text/xmlContent-length: 181examples.getStateName41

SOAP RPC示例代碼

POST /StockQuote HTTP/1.1Host: www.stockquoteserver.comContent-Type: text/xml; charset="utf-8"Content-Length: nnnnSOAPAction: "Some-URI"DIS

我們來分析下該SOAP請求,其目的很簡單,就是得到上次的交易價格,其Operation是SOAP體中的GetLastTradePrice方法,從方法名我們不難看出,其實就是一個簡單的查詢。但是卻封裝成復(fù)雜的SOAP協(xié)議體,且本來基于HTTP協(xié)議的查詢請求,GET語義就能夠滿足,但其卻用POST方法來做。我們知道從HTTP協(xié)議的角度,各個HTTP Verb都有其標(biāo)準(zhǔn)規(guī)范,如下圖所示:

即POST請求通常用在資源創(chuàng)建或更新時,而GET則是用在讀取一個資源。這樣做的一個好處就是HTTP協(xié)議是整個WWW都一致使用的協(xié)議,全網(wǎng)范圍內(nèi)有著一致的上下文,而不像SOAP示例中其是讀取資源還是更新資源只有客戶端和服務(wù)器自己知道。統(tǒng)一HTTP Verb帶來的另一個好處就是,Service緩存機制的實現(xiàn)變得很簡單。因為大家都建立在這些Verb規(guī)范的共識之上,可以直接通過請求方法來判斷是否這些內(nèi)容該緩存或者應(yīng)該從緩存讀取。

除了HTTP Verb,REST也基于統(tǒng)一的HTTP Response Code,來表示請求響應(yīng)的狀態(tài)。把HTTP響應(yīng)頭的語義狀態(tài)與應(yīng)用本身的資源請求結(jié)果狀態(tài)統(tǒng)一。如Amazon S3 REST風(fēng)格的響應(yīng)碼:

便不會再像RPC風(fēng)格的響應(yīng)那樣,響應(yīng)碼是200/OK,但返回的響應(yīng)體卻是Service specific的錯誤碼。完全的HTTP響應(yīng)碼標(biāo)準(zhǔn)定義可以參考HTTP/1.1協(xié)議也有人是這么記的:(

2- URI

利用統(tǒng)一的HTTP Verb, Response Code,也使得Fielding提出的Uniform interface成為可能。另一方面,網(wǎng)絡(luò)上的資源訪問統(tǒng)一接口便是URI,對于Resource-Oriented架構(gòu)模式而言,便需要一個URI能夠清晰無誤的描述一個資源對象。且URI應(yīng)該有層次結(jié)構(gòu),其改變最好能夠以一種客戶端用戶可預(yù)測的方式來進(jìn)行。按照Richardson的說法,一個好的URI需要self-descriptive和Addressibility。

與之相反,如前面提到的,RPC架構(gòu)風(fēng)格往往提供單個Service的全局URI,然后通過SOAP等應(yīng)用協(xié)議來封裝方法和所要獲取的資源。

3- Stateless

Resource-Oriented架構(gòu)的另一個重要特征便是無狀態(tài)性。但就Web

Service而言,狀態(tài)有兩種,一種是應(yīng)用程序狀態(tài),一種是資源狀態(tài)。資源狀態(tài)是Service本身內(nèi)部維持的狀態(tài),其通過統(tǒng)一資源接口暴露給

Client。當(dāng)Client操作一個資源時,如在一個圖片分享網(wǎng)站上上傳了一幅照片,那么從Service的角度,這個資源新產(chǎn)生了,可以給它賦予一個

URI來讓Client進(jìn)行增刪改等資源操作了。這些都是Service需要維護(hù)的狀態(tài)。應(yīng)用程序狀態(tài)是指客戶端的行為。如其訪問了分頁資源,其當(dāng)前所在

的頁數(shù),之前訪問的是哪兒,需不需要再次認(rèn)證。這些都屬于應(yīng)用程序狀態(tài)。REST的風(fēng)格就是,我不會維持這些狀態(tài)。所有的狀態(tài)信息需要Client自己提

供。比如認(rèn)證,客戶端需要每次訪問時都提供認(rèn)證。當(dāng)然這有利有弊,但使得Web Service變得簡單。

III- RESTful該如何評價

前面一章我們試圖通過對比的方法來理解REST架構(gòu),但我們該如何定義一個Web Services是RESTful的,或不是RESTful的呢?還是Richardson這哥么,他把REST的一些原則特性細(xì)化成一系列可執(zhí)行的步驟,提出了自己的REST成熟度模型。并再一次QCon的演講中把它形象化為REST榮耀之路

圖中把REST成熟度分為0-3級。

第0級是指沒有使用REST,仍然淹沒在RPC的人流中。把HTTP協(xié)議當(dāng)做一種跟Web上遠(yuǎn)程系統(tǒng)交互的傳輸機制,所謂的POX(Plain Old XML)指的就是與SOAP,XML,JSON RPC類似的機制。

第1級是指引入了Resource的概念。交互的方式不再是單一的Endpoint下的傳輸體中不同方法的封裝,而是能夠針對每一個獨立的資源實體,有相應(yīng)的URI。我們的操作方法不再是零散的參數(shù)傳遞,而是在這個資源實體上的方法調(diào)用。

第2級是指引入了我們前面提到的HTTP Verb和Response Code。我們不依賴于傳入自定義的操作方法,而是利用HTTP協(xié)議本身的優(yōu)勢。當(dāng)我們想查詢一個資源時候用GET,想更新一個資源時用PUT,想創(chuàng)建一個資源時用POST關(guān)于POST和PUT的差別,統(tǒng)一的觀點是:當(dāng)Client知道待更新資源的URI,就用PUT。當(dāng)Client不知道待更新資源的URI,只是把資源給Service,讓它來決定資源的URI,就用POST。

。

第3級就是Fielding所說的Hypertext As the Enginee of Application State(HATEOAS)。也就指示了State Transfer的含義。通過Hypermedia的響應(yīng)來引導(dǎo)Client的下一步行為。當(dāng)Client能夠以一種可以預(yù)測的方式來探索Service的調(diào)用接口。更詳細(xì)的介紹可以參考末尾的引用。

當(dāng)然這個成熟度模型可以很好的表達(dá)REST,但并不是唯一的標(biāo)準(zhǔn),也有很多人提出了質(zhì)疑和自己的看法。但山人認(rèn)為,它至少能夠幫助我們以一種邏輯的方式讓我們對什么是RESTful有了更為深入和清晰的理解。

So long, and thanks for all the fish!

參考

[1].Do-You-Really-Know-Why-You-Prefer-Rest-over-Rpc.

[2].Rest Arch Style

[3].Measuring-Rest

[4].Rest in Practice

[5].Richardson Maturity Model

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容