SOAP(Simple Object Access Protocal) 技術(shù)有助于實現(xiàn)大量異構(gòu)程序和平臺之間的互操作性,從而使存在的應(yīng)用能夠被廣泛的用戶所訪問。SOAP是把成熟的基于HTTP的WEB技術(shù)與XML的靈活性和可擴(kuò)展性組合在了一起。 這篇文章帶你全面回顧對象遠(yuǎn)程進(jìn)程調(diào)用(ORPC)技術(shù)的歷程,以幫助你理解SOAP技術(shù)的基礎(chǔ),以及它克服存在技術(shù)(如CORBA和DCOM)的許多缺陷的方法。隨后講述詳細(xì)的SOAP編碼規(guī)則,并把焦點放在SOAP是怎樣映射到存在的ORPC概念上的。 引言: 當(dāng)我在1984年開始把計算作為我的職業(yè)的時候,大多數(shù)程序員并不關(guān)心網(wǎng)絡(luò)協(xié)議。但是在九十年代網(wǎng)絡(luò)變得無所不在,現(xiàn)在如果有誰使用計算機卻不使用某種形式網(wǎng)絡(luò)連接是很難以想象的。今天,一般的程序員對建立可擴(kuò)展的分布式應(yīng)用表現(xiàn)出更大的興趣,而不再只是關(guān)注于用MFC實現(xiàn)個性化的可浮動半透明非矩形的Coolbars了。 程序員通常喜歡用編程模型來思考問題,而很少考慮網(wǎng)絡(luò)協(xié)議。盡管這樣做通常是很好的,但在這篇文章中我將討論的SOAP是一個沒有明顯的編程模型的網(wǎng)絡(luò)協(xié)議。這并不意味著SOAP的體系結(jié)構(gòu)從根本上會改變你編程的方式。相反,SOAP的一個主要目標(biāo)是使存在的應(yīng)用能被更廣泛的用戶所使用。為了實現(xiàn)這個目的,沒有任何SOAP API或SOAP 對象請求代理(SOAP ORB),SOAP是假設(shè)你將使用盡可能多的存在的技術(shù)。幾個主要的CORBA廠商已經(jīng)承諾在他們的ORB產(chǎn)品中支持SOAP協(xié)議。微軟也承諾在將來的COM版本中支持SOAP。 DevelopMentor已經(jīng)開發(fā)了參考實現(xiàn),它使得在任何平臺上的任何Java或Perl程序員都可以使用SOAP。 在SOAP后面的指導(dǎo)理念是“它是第一個沒有發(fā)明任何新技術(shù)的技術(shù)”。SOAP采用了已經(jīng)廣泛使用的兩個協(xié)議:HTTP和XML。HTTP用于實現(xiàn)SOAP的RPC風(fēng)格的傳輸,而XML是它的編碼模式。采用幾行代碼和一個XML解析器,HTTP服務(wù)器(如MS的IIS或Apache)立刻成為了SOAP的ORBs。 因為目前超過一半的Web服務(wù)器采用IIS或Apache, SOAP將會從這兩個產(chǎn)品的廣泛而可靠的使用中獲取利益。這并不意味著所有的SOAP請求必須通過Web服務(wù)器來路由,傳統(tǒng)的Web 服務(wù)器只是分派SOAP請求的一種方式。因此Web服務(wù)如IIS或Apache對建立SOAP使能的應(yīng)用是充分的,但決不是必要的。 正如這篇文章將要描述的,SOAP簡單地用XML來編碼HTTP的傳輸內(nèi)容。SOAP最常用的應(yīng)用是作為一個RPC協(xié)議。為了理解SOAP怎樣工作,有必要簡要回顧一下RPC協(xié)議的歷史。 RPCs的歷史 建立分布式應(yīng)用的兩個主要通信模型是消息傳送(經(jīng)常與隊列組合在一起)和請求/響應(yīng)。消息傳遞系統(tǒng)允許通信任何一方在任何時間發(fā)送消息。請求/響應(yīng)協(xié)議把通信模式限制在請求/響應(yīng)的雙方。基于消息的應(yīng)用強烈地意識到它們正在與外部的并行進(jìn)程進(jìn)行通信,并且需要一個顯式的設(shè)計風(fēng)格?;谡埱?響應(yīng)的應(yīng)用更象一個單進(jìn)程的應(yīng)用,因為發(fā)送請求的應(yīng)用或多或少被阻塞直至收到來自另一個進(jìn)程的響應(yīng)。這使得請求/響應(yīng)通信自然地適合于RPC應(yīng)用。 盡管消息通信和請求/響應(yīng)各有他們的優(yōu)點,他們都是可以用對方來實現(xiàn)的。消息系統(tǒng)可以用較底層的請求/響應(yīng)協(xié)議來建立。如微軟的Message Queue Server (MSMQ)內(nèi)部采用了DCE RPC來建立大多數(shù)的控制邏輯。RPC系統(tǒng)也可以采用較底層的消息系統(tǒng)來建立。MSMQ提供的關(guān)聯(lián) ID正是為了這個目的。不管評價如何,大多數(shù)的應(yīng)用仍趨向于使用RPC協(xié)議,因為它們廣泛的使用,它們更簡單的設(shè)計,以及更自然的到傳統(tǒng)的編程技術(shù)的映射。 在八十年代,兩個主要的RPC協(xié)議是Sun RPC 和DCE RPC。最流行的Sun RPC應(yīng)用是大多數(shù)UNIX系統(tǒng)所使用的Network File System (NFS)。最流行的DCE RPC應(yīng)用則是Windows NT?,它采用DCE RPC 協(xié)議來實現(xiàn)許多系統(tǒng)服務(wù)。這兩個協(xié)議被證明適用于很大范圍的應(yīng)用。但是,在八十年代末期,面向?qū)ο蠹夹g(shù)的風(fēng)靡使軟件界沉迷于在面向?qū)ο笳Z言和基于RPC的通信之間建立一個紐帶。 在九十年代產(chǎn)生的對象RPC (ORPC) 協(xié)議正是試圖把面向?qū)ο蠛途W(wǎng)絡(luò)協(xié)議聯(lián)系起來。ORPC 和 RPC 協(xié)議的主要不同是ORPC代碼化了從通信終端到語言級對象的映射。在每個ORPC請求的頭中都有一個cookie,服務(wù)器端的程序能用它來定位在服務(wù)器進(jìn)程中的目標(biāo)對象。通常這個cookie只是一個對數(shù)組的索引,但其它技術(shù)也經(jīng)常被使用,如用符號名作為Hash表的鍵。 目前兩個主要的OPRC協(xié)議是DCOM 和 CORBA的 Internet Inter-ORB Protocol (IIOP) 或更一般的General Inter-ORB Protocol (GIOP)。DCOM和IIOP/GIOP的請求格式非常相似。兩個協(xié)議都用一個對象端點ID來確定目標(biāo)對象,用方法標(biāo)識符來決定調(diào)用哪個方法。 這兩個協(xié)議主要有兩點不同:主要的一點不同是采用IIOP/GIOP時,接口標(biāo)識符是隱含的,因為一個給定的CORBA對象只實現(xiàn)一個接口(盡管OMG當(dāng)前正在進(jìn)行每個對象有多個接口支持的標(biāo)準(zhǔn)化工作)。DCOM與IIOP/GIOP請求的另一個細(xì)微差別是在傳輸體中參數(shù)值的格式。在DCOM中,傳輸體用網(wǎng)絡(luò)數(shù)據(jù)表達(dá)(NDR)的格式來寫,在IIOP/GIOP中,傳輸體用公共數(shù)據(jù)表達(dá)(CDR)的格式來寫。NDR和 CDR分別處理在各種平臺上的不同的數(shù)據(jù)表達(dá)。但是在這兩種格式之間有一些小的差別,這使它們相互之間并不兼容。 在ORPC與RPC協(xié)議之間的另一個重要的不同是通信端點的命名方式。在ORPC協(xié)議中,對于ORPC端點的一些可傳遞的表達(dá)方式被要求在網(wǎng)絡(luò)之間傳遞對象引用。在CORBA/IIOP,這個表達(dá)方式被稱為可交互的對象引用(IOR)。IORs包含用緊湊格式表達(dá)的尋址信息,使用了它任何CORBA產(chǎn)品都可以決定一個對象端點。在DCOM中,這種表達(dá)方式被稱為OBJREF,它組合了分布的引用計算和端點/對象標(biāo)識。CORBA和DCOM都提供了在網(wǎng)絡(luò)上尋找對象端點的高級機制,但最終這些機制都映射回到了IORs或OBJREFs。 目前的技術(shù)存在的問題? 盡管DCOM和IIOP都是固定的協(xié)議,業(yè)界還沒有完全轉(zhuǎn)向其中任何一個協(xié)議。沒有融合的部分原因是文化的問題所致。而且在當(dāng)一些組織試圖標(biāo)準(zhǔn)化一個或另一個協(xié)議的時候,兩個協(xié)議的技術(shù)適用性就被提出質(zhì)疑。傳統(tǒng)上認(rèn)為DCOM和CORBA都是合理服務(wù)器到服務(wù)器端的通信協(xié)議。但是,二者對客戶到服務(wù)器端的通信都存在明顯的弱點,尤其是客戶機被散布在Internet上的時候。 DCOM 和 CORBA/IIOP都是依賴于單個廠商的解決方案來最大優(yōu)勢地使用協(xié)議。盡管兩個協(xié)議都在各種平臺和產(chǎn)品上被實現(xiàn)了,但現(xiàn)實是選定的發(fā)布需要采用單一廠商的實現(xiàn)。在DCOM的情況下,這意味著每個機器要運行在Windows NT。(盡管DCOM已經(jīng)被轉(zhuǎn)移到其它平臺,但它只在Windows?上獲得了廣泛的延伸)。在CORBA情況下,這意味著每個機器要運行同樣的ORB產(chǎn)品。的確讓兩個CORBA產(chǎn)品用IIOP相互調(diào)用是有可能的,但是許多高級的服務(wù)(如安全和事務(wù))此時通常不是可交互的。而且,任何專門廠商為同樣的機器的通信所作的優(yōu)化很難起作用,除非所有的應(yīng)用被建立在同一個ORB產(chǎn)品上。 DCOM 和CORBA/IIOP都依賴于周密管理的環(huán)境。兩個任意的計算機使得DCOM或IIOP 在環(huán)境之外被成功調(diào)用(calls out of the box)的幾率是很低的。特別是在考慮安全性的時候尤其是這樣。盡管寫一個能成功地運用DCOM或IIOP的緊縮包(shrink-wrap)應(yīng)用是可能的,但這樣做要比基于socket的應(yīng)用要更多地關(guān)注細(xì)節(jié)。這對于乏味但必需的配置和安裝管理任務(wù)特別適用。 DCOM 和 CORBA/IIOP都依賴于相當(dāng)高技術(shù)的運行環(huán)境。盡管進(jìn)程內(nèi)的COM似乎特別簡單,但COM/DCOM遠(yuǎn)程處理程序絕對不只是幾天就解決的事情。IIOP 是一個比DCOM更容易實現(xiàn)的協(xié)議,但兩個協(xié)議都有相當(dāng)多的深奧的規(guī)則來處理數(shù)據(jù)排列、類型信息和位操作。這使得一般的程序員在沒有領(lǐng)會ORB產(chǎn)品或OLE32.DLL的情況下去構(gòu)造一個簡單的CORBA或DCOM調(diào)用也變得很困難。 也許對DCOM和CORBA/IIOP來說,最令人難以忍受的一點是它們不能在Internet 上發(fā)揮作用。對DCOM來說,一般用戶的iMac 或廉價的運行Windows 95的PC 兼容機要想使用你的服務(wù)器執(zhí)行基于領(lǐng)域認(rèn)證幾乎是不可能的。更糟的是,如果防火墻或代理服務(wù)器分隔開了客戶和服務(wù)器的機器,任何IIOP或DCOM包要通過的可能性是很低的,主要是由于大多數(shù)Internet連接技術(shù)對HTTP協(xié)議的偏愛所致。盡管一些廠商如Microsoft, Iona和Visigenic都已經(jīng)建立了通道技術(shù),但這些產(chǎn)品很容易對配置錯誤敏感而且它們是不可交互的。 在一個服務(wù)器群落中這些問題并不能影響DCOM或IIOP的使用。因為在服務(wù)器群落中主機的數(shù)量很少(一般是成百上千,而不是成千上萬),這就抵消了DCOM基于ping的生命周期管理的成本。在服務(wù)器群落中,所有主機被一個公共管理域管理的機率很大,使得統(tǒng)一的配置變得可能。相對少量的機器也能保持商業(yè)ORB產(chǎn)品可控制使用的成本,因為只需要更少量的ORB許可權(quán)。如果只有IIOP在服務(wù)器群落中被使用,就只需要少量的ORB許可權(quán)。最后,在服務(wù)器群落中所有主機有直接的IP連接也是可能的,這就消除了與防火墻相關(guān)的DCOM和 IIOP問題。 HTTP作為一個更好的RPC 在服務(wù)器群落中使用DCOM 和CORBA 是通用的做法,但客戶機則使用HTTP進(jìn)入服務(wù)器群落。HTTP與RPC的協(xié)議很相似,它簡單、配置廣泛,并且對防火墻比其它協(xié)議更容易發(fā)揮作用。HTTP請求一般由Web服務(wù)器軟件(如IIS和Apache)來處理,但越來越多的應(yīng)用服務(wù)器產(chǎn)品正在支持HTTP作為除DCOM和IIOP外的又一個協(xié)議。 象DCOM和IIOP一樣,HTTP層通過TCP/IP進(jìn)行請求/響應(yīng)通信。一個HTTP的客戶端用TCP連接到HTTP服務(wù)器。在HTTP中使用的標(biāo)準(zhǔn)端口號是80,但任何其它端口也能被使用。在建立TCP連接后,客戶端可以發(fā)送一個請求消息到服務(wù)器端。服務(wù)器在處理請求后發(fā)回一個HTTP響應(yīng)消息到客戶端。請求和響應(yīng)消息都可以包含任意的傳輸體的信息,通常用Content-Length和Content-Type的 HTTP 頭來標(biāo)記。下面是一個合法的HTTP請求消息: POST /foobar HTTP/1.1 Host: 209.110.197.12 Content-Type: text/plain Content-Length: 12 Hello, World 你可能已經(jīng)注意到HTTP頭只是一般文本。這使得用包檢查程序或基于文本的Internet工具(如telnet)來診斷HTTP問題變得更容易。HTTP基于文本的屬性也使得HTTP更容易適用于在Web開發(fā)中流行的低技術(shù)水平的編程環(huán)境。 HTTP請求的第一行包含三個組件:HTTP方法,請求-URI,協(xié)議版本。在前面的例子中,這些分別對應(yīng)于POST, /foobar, 和 HTTP/1.1。Internet工程任務(wù)組(IETF)已經(jīng)標(biāo)準(zhǔn)化了數(shù)量固定的HTTP方法。GET是HTTP用來訪問Web的方法。 POST是建立應(yīng)用程序的最常用的HTTP方法。和GET不一樣,POST允許任意數(shù)據(jù)從客戶端發(fā)送到服務(wù)器端。請求URI (Uniform Resource Identifier)是一個HTTP服務(wù)器端軟件,它用來識別請求的目標(biāo)的簡單的標(biāo)識符(它更象一個IIOP/GIOP object_key 或一個DCOM IPID)。關(guān)于URIs更多的信息請參照"URIs, URLs, and URNs"。在這個例子中協(xié)議的版本是HTTP/1.1, 它表示遵守RFC 2616的規(guī)則。HTTP/1.1比HTTP/1.0多增加了幾個特性,包括對大塊數(shù)據(jù)傳輸?shù)闹С忠约皩υ趲讉€HTTP請求之間保持TCP連接的支持。 請求的第三行和第四行指定了請求體的尺寸和類型。Content-Length 頭指定了體信息的比特數(shù)。Content-Type類型標(biāo)識符指定MIME類型為體信息的語法。HTTP (象 DCE一樣) 允許服務(wù)器和客戶端協(xié)商用于編制信息的傳輸語法。大多數(shù)DCE應(yīng)用采用NDR.。大多數(shù)Web應(yīng)用采用text/html 或其它基于文本的語法。 注意在上面樣例中Content-Length頭與請求體之間的空行。不同的HTTP頭被carriage-return/行碼序列劃定界限。這些頭與體之間用另外的carriage-return/行碼序列來劃定界限。請求接著包括原始字節(jié),這些字節(jié)的語法和長度由Content-Length和Content-Type HTTP 頭來識別。在這個例子中,內(nèi)容是十二字節(jié)的普通文本字符串"Hello, World"。 在處理了請求之后,HTTP服務(wù)器被期望發(fā)回一個HTTP響應(yīng)到客戶端。響應(yīng)必須包括一個狀態(tài)代碼來表示請求的結(jié)果。響應(yīng)也可以包含任意的體信息。下面是一個HTTP響應(yīng)消息: 200 OK Content-Type: text/plain Content-Length: 12 dlroW ,olleH 在這個例子中,服務(wù)器返回狀態(tài)代碼200,它是HTTP中標(biāo)準(zhǔn)的成功代碼。如果服務(wù)器端不能破解請求代碼,它將返回下列的響應(yīng): 400 Bad Request Content-Length: 0 如果HTTP服務(wù)器決定到目標(biāo)URI的請求應(yīng)該臨時轉(zhuǎn)向另外的一個不同的URI,下列響將被返回: 307 Temporarily Moved Location: http://209.110.197.44/foobar Content-Length: 0 這個響應(yīng)告知客戶,請求將能夠通過重新傳遞它到在Location頭中指定的地址來被滿足。 所有的標(biāo)準(zhǔn)狀態(tài)碼和頭都在RFC 2616中被描述。它們中很少的內(nèi)容與SOAP用戶直接相關(guān),但有一個明顯的例外。在HTTP/1.1,底層的TCP連接在多個請求/響應(yīng)對之間重用。HTTP Connection頭允許客戶端或服務(wù)器中任何一方關(guān)閉底層的連接。通過增加下列HTTP頭到請求或響應(yīng)中,雙方都會要求在處理請求后關(guān)閉它們的TCP連接: Connection: close 當(dāng)與HTTP/1.0軟件交互時,為了保持TCP連接,建議發(fā)送方加入下列HTTP頭到每個請求或響應(yīng)中: Connection: Keep-Alive 這個頭使缺省的HTTP/1.0協(xié)議在每次響應(yīng)后重新開始TCP連接的行為無法使用。 HTTP的一個優(yōu)點是它正被廣泛的使用和接受。圖4表示了一個簡單的Java程序,它發(fā)送前面表示的請求并從響應(yīng)中解析出結(jié)果字符串。 下面則是一個簡單的C程序用CGI來讀取來自HTTP請求的字符串并通過HTTP響應(yīng)把它的逆序串返回。 #include <stdio.h> int main(int argc, char **argv) { char buf[4096]; int cb = read(0, buf, sizeof(buf)); buf[cb] = 0; strrev(buf); printf("200 OK\r\n");p> printf("Content-Type: text/plain\r\n"); printf("Content-Length: %d\r\n", cb); printf("\r\n"); printf(buf); return 0; 服務(wù)器的實現(xiàn)是用Java servlet,以避免CGI的每個請求一個進(jìn)程的開銷。 一般 來說CGI是花費代價最小的寫HTTP服務(wù)器端代碼的方法。實際上,每一個HTTP服務(wù)器端產(chǎn)品都提供了一個更有效的機制來讓你的代碼處理一個HTTP請求。IIS提供了ASP和ISAPI作為寫HTTP代碼的機制。Apache允許你用運行在Apache后臺程序中的 C或Perl來寫模塊。大多數(shù)應(yīng)用服務(wù)器軟件允許你寫Java servlet,COM組件,EJB Session beans或基于可攜帶對象適配器(POA)接口的CORBA servants。 |
|