基本概念
1. rest和rpc架構的概念
REST架構:方法信息(method information)都在HTTP方法(HTTP method)里.
面向資源的架構(ROA): 作用域信息(scoping information)都在URI里.
如果一個系統架構的實現, 完全滿足以上兩條,則可以認為是一個純正的rest架構, 如果都不滿足,則是一個典型的rpc架構。通常來說,更常見的可能是一種rest-rpc 混合架構.
作者也指出:
許多只讀的Web服務,盡管它們起初也許是按RPC風格設計的,但它們都可稱得上是完全REST式和面向資源的!?但是,如果該服務允許客戶端修改數據的話,就會出現客戶端所使用的HTTP方法與真正的方法信息不一致的情況——這樣它就不具備REST式服務的特征了。?像這樣的服務,我稱之為REST-?RPC混合服務。
RPC式架構:方法信息和作用域信息都在信封(envelope)或報頭(headers)里。 具體采用哪種信封,并不影響這里的分類,不過HTTP是一種常見信封格式.
RPC將服務器看作是由一些過程組成,客戶端調用這些過程來執行特定的任務。這種特定決定了rpc調用的高耦合性,不過就應用開發的角度來說,很多人不會去關心這個問題。
分布式對象架構:分布式對象架構將服務器看做遠程對象的組合,通過代理調用遠程對象來掩飾本地對象和遠程對象的差別。分布式對象結構的主要缺點是粒度的控制問題,另外某種意義上分布式對象結構依然是rpc風格的,只不過做了更好的掩飾。
2. big soap webservice中的rpc和document的概念
順手補習一下 ws * 中的rpc和document的概念。
常見兩種編碼綁定方式, rpc風格和document風格, 雖然后者理論上號稱是非rpc方式的面向消息的封裝,并具有一些理論上的優點,但實際情況仍然是rpc方式。
可以從xml文件的結構來看兩種模式的差異
rpc風格
請求包
<?xml?version="1.0"??>
<soapenv:Envelope
??????xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/"
??????xmlns:xsd="http://www.w3.org/2001/XMLSchema"
??????xmlns:ns1="http://item.service.soap.soajava.packt.com/">
??<soapenv:Body>
????<ns1:insert> // method name bingding
????<arg0> // parameter
??????<code>XY</code>
??????<description>xy?desc</description>
??????<id>26</id>
????</arg0>
????</ns1:insert>
??</soapenv:Body>
</soapenv:Envelope>
一個rpc調用總是由4部分組成
- A remote address
- A method (or operation) name
- A sequence of parameters
- A synchronous response
這4部分基本和一個程序語言的方法調用一致。
rpc風格的wsdl文件描述
????? <message?name="insert">
?????????<part?name="itemParam"?type="tns:item"></part>
?????????<part?name="categoryParam"?type="xsd:string"></part>
??????</message>
??????<message?name="insertResponse">
?????????<part?name="return"?type="tns:outcome"></part>
??????</message>
??????<portType?name="ItemWs">
?????????<operation?name="insert"?parameterOrder=?
?????????????????????????????????????"itemParam?categoryParam">
????????????<input?message="tns:insert"></input>
????????????<output?message="tns:insertResponse"></output>
?????????</operation>
??????</portType>
??????<binding?name="ItemWsPortBinding"?type="tns:ItemWs">?
?????????<soap:binding?style="rpc"?
????????????????????transport="http://schemas.xmlsoap.org/soap/http">
?????????</soap:binding>
?????????<operation?name="insert">
????????????<soap:operation?soapAction=""></soap:operation>?
????????????<input>?
???????????????<soap:body?use="literal"?namespace=?
???????????????????????"http://item.service.soap.soajava.packt.com/">
???????????????</soap:body>?
????????????</input>?
Document 風格
請求包
??<ns1:itemInsertRequestParam> // no method call here
????????????<category>A</category>
????????????<item>
???????????????<code>XY</code>
???????????????<description>xy?desc</description>
???????????????<id>26</id>
????????????</item>
??</ns1:itemInsertRequestParam>
雖然看起來差別不大,但是此處已經沒有所謂明顯的方法調用特征,無方法名和參數綁定,即請求包是以所謂document為處理核心的,而document可以理解為一種resouce或者message。(呵呵,有點自欺欺人)。
更大的差別在wsdl的描述上
??<message?name="insert">?
?????????<part?element="tns:itemInsertRequestParam"
??????????????????name="itemInsertRequestParam"></part>? // no type attribute here.
? </message>
??????
??????<binding?name="ItemWsPortBinding"?type="tns:ItemWs">
?????????<soap:binding?style="document" message里只包含一個part,也不再使用type熟悉申明。據說這樣的差別決定了可以用xsd對文檔進行校驗(我沒完全明白)。
雖然實際上rpc和document差別不大,但是理論上存在2個重大差異
1. document風格不直接和方法綁定,所以方法變化時,比如增加一個屬性時,不一定會影響客戶端代碼。
2. document風格能提供對文檔的校驗模式。
但實際上, webservice中的 document風格綁定,其實還是rpc的。從這可以看出big web service是多么的無聊。
實際應用中,這2種風格的差別會引起很多問題, 一些傳統的老舊應用基本是rpc風格的,而某些應用和webservice實現則只提供document的支持。這會部分導致兼容性問題,雖然理論上,新的總是兼容舊的,但實際問題多多。
順便說一個實際工作中碰到的問題,在使用domino7將服務發布成document風格的web service時,我們有時候(牛就牛在這有時候)會出現服務調用亂竄的問題, 客戶端提交的服務調用會亂竄到同參數的其他服務中,充分體現了document風格不以方法名綁定的實質,nnd。
另外,是否正是因為soap這種先天性的rpc架構缺陷,導致了必然的兼容性和復雜性問題?
為什么要使用rest架構對此問題我其實長期以來一直存在一個本質的誤解。 我之所以喜歡用restful 的web service,其實更直接的原因是我實在討厭soap的big web service。 使用rest我至少得到了2個好處。
1. 開發效率和執行效率的顯著提高
2. 回避了兼容性問題,特別是異構系統間。
好吧,但是象ror那樣,把所有內容都發布成了CRUD的操作的rest,我還是一直比較反感的,實在看不出其中的好處。我一直覺得,遠程服務應該是比較大粒度的東西,不應該將所有的資源都服務化。 而旺財同學曾經給我看過infoq上一篇文章,關于rest的那10個問題,看完以后我還是繼續迷糊,好像一個問題都沒有解釋清楚。
不過今天突然明白了。rest的意義在于通過將數據操作的資源化,給客戶端的使用提供了足夠的靈活性,這是傳統結構難以比擬的。這其實是一個視角變換的問題。
靜態網頁比動態的bbs更容易被檢索使用也是由于這種信息的資源化,資源化的結果是給客戶端的玩法提供近乎無限的可能性。rest其實是一種以客戶端使用為主要核心的結構。
其實想想自己平時在應用開發中對數據的操作也能對應起來。一般來說做一個業務系統開發,對數據我會干2件事。
1. 使用技巧實現一個萬能dao,或者通過模板工具,將所有數據表映射到對象并創建對應的CRUD操作甚至關聯操作。
這樣做的目的并不在于系統中所有的表都需要做crud操作,而是試圖把對數據庫的操作釋放為標準的對象操作,屏蔽掉數據庫操作,提高程序員操作的靈活性。
2. 對應非CRUD的操作, 則重新編寫專門的代碼實現。
而對應的 REST 的 過程
1. 將數據的CRUD操作資源化發布。
?? 可以考慮c/s結構的開發, 如果未有此種資源化會增加客戶端和服務器多少工作量?
2. 對于復雜的操作需求,編寫專門服務實現。
?? 這個操作有可能是rpc風格的。
? ?
這2種做法基本一致, 都是按2,8 原則對粗粒度和細粒度進行組合。 而我之前的迷糊,其實來源于以往分布式對象架構經驗的困擾,EJB/RMI方面的苦難經歷已經給我們洗腦,分布式結構,細粒度總是不好的,靈活總是難以控制的,所以我們習慣于限制客戶端的可操作性。
REST的架構, 某種意義應該理解為客戶端應用導向的架構,關心的是能給予客戶端更多的靈活性而不是更多的限制。
服務和客戶的對應關系,總是1對n的關系。 從這個角度看,rest是天生更適合SOA的, 比SOAP 要合適的多。
但是如何有效又簡潔而且便宜的解決安全問題? 這個還需要繼續研究。