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