常見的三種Web服務架構

相互競爭的服務架構

The Competing Architectures

摘自《RESTful Web Services中文版

我們已經給出了“不同Web服務會有不同做法”的兩個主要問題,現在要據此對不同風格的Web服務進行分類了。根據我的研究,常見的Web服務架構主要有三種:REST式架構、RPC式架構和REST-RPC混合架構。下面依次對它們進行介紹。

REST式、面向資源的架構

RESTful, Resource-Oriented Architectures

本書的主題是符合REST風格的Web服務架構——按照Roy Fielding博士論文裏的評判標準,它們可以獲得很高的得分。現在,雖然許多架構從技術上說是REST式的(注3),但我希望關注那些最適合Web服務的架構;所以,當我談及RESTWeb服務時,我指的是那些具備Web特徵的服務——稱它們爲面向資源的(resource-oriented)。將在第3章通過一個真實的Web服務——Amazon S3Simple Storage Service)來介紹面向資源的REST的基本概念,然後在第4章,向你逐個介紹REST的標誌特徵,並定義一種非常適合RESTWeb服務的架構——面向資源的架構(Resource-Oriented Architecture)。

REST式架構意味着,方法信息(method information)都在HTTP方法(HTTP method)裏;面向資源的架構(ROA)意味着,作用域信息(scoping information)都在URI——二者結合起來是很強大的。一個面向資源的RESTWeb服務,通過HTTP請求的第一行(如“GET /reports/open-bugs HTTP/1.1”)就能基本瞭解客戶端要做什麼了,HTTP請求的其餘部分只是具體細節而已。實際上,很多HTTP請求只要第一行就行了。如果HTTP方法跟方法信息對不上,那麼服務就算不上是REST式的;如果作用域信息不放在URI裏,那麼服務就不是面向資源的。雖然並非只有這兩條要求,但它們是很好的經驗。

l   提供Atom發佈協議(http://www.ietf.org/html.char ters/atompub-charter.html)及其變型的服務,例如GDatahttp://code.google.com/apis/gdata/

l   Amazon S3Simple Storage Service)(http://aws.amazon.com/s3

l   Yahoo!提供的大部分Web服務(http://developer.yahoo.com/

l   許多其他未採用SOAP的、只讀的Web服務

l   靜態網站

l   很多Web應用(尤其是像搜索引擎這種只讀的)

每當談到非REST式架構或非面向資源的架構時,我都是有一定目的的。這一章將在Programmable Web的背景之下,對RESTWeb服務加以全面考察。在第2章會提到一些真實的Web服務,並指出:無論一個服務是否正好符合我所推薦的架構,你都可以採用同樣的客戶端工具訪問它。在第10章,會就“如何設計programmable web”這一久遠的話題發表觀點。

RPC式架構

RPC-Style Architectures

RPCWeb服務(RPC-style Web Service)通常從客戶端收到一個充滿數據的信封(envelope),然後發回一個同樣充滿數據的信封。RPC式架構意味着:方法信息和作用域信息都在信封(envelope)或報頭(headers)裏。具體採用哪種信封,並不影響這裏的分類,不過HTTP是一種常見信封格式(畢竟,採用HTTP才稱得上是Web服務)。另一種常見的信封格式是SOAP(把SOAP信封放在HTTP信封裏,在HTTP上傳送SOAP文檔)。各個RPC式服務採用自己的詞彙,就像計算機程序一樣(你每次寫程序,定義的函數名稱都不相同)。而RESTWeb服務則相反,它們共用一套標準詞彙,即HTTP方法。REST式服務裏的每個對象都具有統一的基本接口。

XML-RPC是最典型的RPC架構的例子。雖然目前XML-RPC主要是一種遺留協議(legacy protocol)了,但由於它相對簡單,而且比較容易解釋,所以我還是準備從它開始講起。示例1-11所示的Ruby客戶端用於訪問一個XML-RPC服務,該服務的作用是查詢具有統一產品代碼(Universal Product Code)的產品。

示例1-11:一個訪問XML-RPC服務的例子:根據UPC查詢產品

#!/usr/bin/ruby -w

# xmlrpc-upc.rb

 

require 'xmlrpc/client'

def find_product(upc)

   server = XMLRPC::Client.new2('http://www.upcdatabase.com/rpc')

   begin

      response = server.call('lookupUPC', upc)

   rescue XMLRPC::FaultException => e

      puts "Error: "

      puts e.faultCode

      puts e.faultString

   end

end

 

puts find_product("001441000055")['description']

# "Trader Joe's Thai Rice Noodles"

XML-RPC服務就像C語言一樣,你可以調用一個帶參數(“001441000055”)的函數lookupUPC),並獲得返回值。方法信息(函數名)和作用域信息(參數)都放在XML文檔(如示例1-12所示)裏。

示例1-12:一個描述XML-RPC請求的XML文檔

<?xml version="1.0" ?>

 <methodCall>

  <methodName>lookupUPC</methodName>

  <params>

   <param><value><string>001441000055</string></value></param>

 </params>

</methodCall>

這個XML文檔是放在信封裏傳給服務器的。這裏的信封(envelope)就是一個HTTP請求,它由HTTP方法、URI、報頭和實體主體等部分組成,其中實體主體就是上面的XML文檔(如示例1-13所示)。

示例1-13:一個包含了描述XML-RPC請求的XML文檔的HTTP信封

POST /rpc HTTP/1.1

Host: www.upcdatabase.com

User-Agent: XMLRPC::Client (Ruby 1.8.4)

Content-Type: text/xml; charset=utf-8

Content-Length: 158

Connection: keep-alive

 

<?xml version="1.0" ?>

<methodCall>

 <methodName>lookupUPC</methodName>

 ...

</methodCall>

上述HTTP信封裏的XML文檔,將隨你所調用方法的不同而有所變化,但HTTP信封的格式總是不變的。無論你對這個UPC查詢服務提什麼請求,URI總是http://www. upcdatabase.com/rpcHTTP方法總是POST。簡單地說,XML-RPC服務未採用HTTP的很多特性;它只暴露一個URI(稱爲“端點”),並且該URI只支持一種HTTP方法——POST方法。

REST式服務爲不同的作用域信息暴露不同的URI;而RPC式服務一般爲每個“文檔處理器”(用於打開信封,並把信封轉換爲軟件指令)暴露一個URI。我們做個對比,假設上述UPC查詢服務被設計爲一種REST式架構的話,那麼其客戶端代碼將如示例1-14所示。

示例1-14:假想的示例代碼:一個RESTUPC查詢服務

require 'open-uri'

upc_data = open('http://www.upcdatabase.com/upc/00598491').read()

...

 

這裏,方法信息包含在HTTP方法裏(默認的HTTP方法是GET,它對應於示例1-13中的lookupUPC),作用域信息包含在URI裏。這個假想的服務暴露的URI不只一個,每個UPC代碼都有與之對應的URI。與示例1-13不同的是,這裏的HTTP信封是空的——它是一個沒有實體主體的HTTP GET請求。

另一個RPC式服務的例子可以參見示例1-8Google SOAP API是一個採用SOAP作爲信封格式的RPC式服務。

較多采用或只採用HTTP POST的服務,多半是RPC式服務。雖然這不是絕對的,但至少可以說明該服務沒有把HTTP方法用於表達方法信息。如果一個REST式服務過多地採用HTTP POST,那麼它就容易演變爲REST-RPC混合架構。

下面是一些知名的RPCWeb服務的例子:

l   所有采用XML-RPC的服務

l   幾乎所有的SOAP服務(這一點是有爭議的,本章後面的“Programmable Web涉及的技術”一節對此進行了探討)

l   少部分Web應用(通常是沒設計好的)

REST-RPC混合架構

REST-RPC Hybrid Architectures

這一術語是我創造的,它用於形容那些介於REST式架構與純RPC式架構之間的Web服務。這些服務通常是由那些對真實Web應用懂得比較多,但對REST理論不精的程序員們創建的。

我們再次回顧一下這個調用Flickr Web服務時使用的URIhttp://www.flickr.com/services/ rest?api_key=xxx&method=flickr.photos.search&tags=penguin。儘管URI裏包含“rest”字樣,但它顯然是一個採用HTTP信封的RPC式服務。另一方面,它的作用域信息(“具有‘penguin’標籤的照片”)是放在URI裏的——從這一點看,它跟REST式面向資源的服務有點相像;不過它的方法信息(“搜索照片”)也被放在URI裏了,而前面說過,對於REST式服務,方法信息應該放在HTTP方法裏,其餘部分全部作爲作用域信息。看來,這個服務只是把HTTP當作信封格式來用,然後按照自己的意願來放置方法信息和作用域信息——這是一個RPC式服務,鑑定完畢!

不過,我們來看示例1-15

示例1-15:一個向Flickr Web服務發HTTP請求的例子

GET services/rest?api_key=xxx&method=flickr.photos.search&tags=penguin HTTP/1.1

Host: www.flickr.com

這是當客戶端調用Flickr Web服務時發出的HTTP請求。這裏看上去,貌似方法信息是在HTTP方法裏的。 這個請求的意圖是獲取(GET)數據。 獲取什麼數據呢?一個搜索“具有‘penguin’標籤的照片”的結果列表。原先貌似方法信息的數據(“搜索照片”),現在看上去像是作用域信息(“photos/tag/penguin”)了。剛纔那個被鑑定爲RPC式的服務,現在呈現出REST風格了。

這是一個錯覺。一個RPC式服務採用普通老式HTTPPlain Old HTTP)作爲信封格式,且方法信息和作用域信息剛好都在HTTP請求的URI路徑裏的話,就會產生這種錯覺。假如HTTP方法是GET,並且請求服務的意圖也是“獲取(GET)”信息的話,就會很難分辨方法信息是在HTTP方法裏,還是在URI裏了。所以你會把一個RPC式服務的HTTP請求看成是RESTWeb服務的HTTP請求。這個HTTP請求裏可能含有“method=flickr. photos.search”這樣的信息,但這個信息會被誤認爲是作用域信息(就像“photos/”和“search/”是作用域信息一樣)。這些RPC式服務,不經意間或多或少地帶着點RESTWeb服務的特徵。它們只是把HTTP作爲一種信封格式來用,不過它們使用HTTP信封的方式可能剛好跟REST式服務的做法雷同。

許多隻讀的Web服務,儘管它們起初也許是按RPC風格設計的,但都可稱得上是完全REST式和麪向資源的!但是,如果該服務允許客戶端修改數據的話,就會出現客戶端所使用的HTTP方法與真正的方法信息不一致的情況——這樣它就不具備REST式服務的特徵了。像這樣的服務,我稱之爲REST-RPC混合服務。

舉個例子。即使客戶端的意圖是修改數據,Flickr Web API仍舊讓客戶端使用HTTP GET。如果要刪除一個照片,你需要向一個包含“method=flickr.photos.delete”的URI發出GET請求,儘管你的這個請求的意圖並不是獲取(GET)數據,如我在第5章所講。Flickr Web API是一種REST-RPC混合架構:當客戶端通過GET方法獲取數據時,它是REST式的;當客戶端通過GET方法修改數據時,它是RPC式的。

一些知名的REST-RPC混合Web服務包括:

l   del.icio.us API

l   Flickr Web API

l   許多被說成是REST式架構的Web服務

l   大部分Web應用

從設計的角度來看,我認爲不會有人特意把服務設計爲REST-RPC混合架構。由於HTTP工作方式的原因,任何採用普通HTTP並暴露多個URIRPC式服務,往往最終成爲REST式架構或混合架構。許多程序員按他們設計Web應用的方式來設計Web服務,並最終形成混合架構的服務。

混合架構的存在已經造成了不少混亂。從事Web應用設計的人容易設計出REST-RPC混合架構,而且他們常常聲稱這種混合架構是REST式架構——他們仍在以設計human web的方式來設計Web服務。已經有不少功夫花費在分辨REST式架構與其他架構上了。我把“其他架構”稱爲REST-RPC混合架構,這是衆多新詞中的一個,我認爲這個新詞是看待這些常見而令人困惑的服務最準確有效的方式。假如你知道它們的其他稱呼(在寫本書的時候,“HTTP+POX”是最流行的),不妨繼續往下讀,後面我會用我自己的語言來解釋這些其他術語。

發佈了4 篇原創文章 · 獲贊 6 · 訪問量 7萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章