摘要:本文概要說明了在通過 SOAP 進(jìn)行 RPC 調(diào)用時(shí)當(dāng)前實(shí)際存在的互操作性問題,同時(shí)討論了導(dǎo)致互操作性問題的三個(gè)
因素:HTTP 問題、XML 問題和 SOAP 間斷性。
簡(jiǎn)介
當(dāng)前有多種創(chuàng)建應(yīng)用程序的平臺(tái)。但每種平臺(tái)都習(xí)慣于使用自身的協(xié)議(本質(zhì)上通常是二進(jìn)制代碼)來實(shí)現(xiàn)機(jī)器間的集
成。因此,跨平臺(tái)的應(yīng)用程序在數(shù)據(jù)共享方面的能力相當(dāng)有限。認(rèn)識(shí)到這些限制后,人們一直在致力于建立有關(guān)數(shù)據(jù)格式
和數(shù)據(jù)交換方面的標(biāo)準(zhǔn),藉此以實(shí)現(xiàn)“不論服務(wù)采用何種軟件,使用何種硬件,都能夠跨越這一傳統(tǒng)的界限以 Web 的形式
無縫地將它們集成在一起”這一遠(yuǎn)景目標(biāo)。目前,這一目標(biāo)已迅速發(fā)展成為一種新的計(jì)算范例。
該目標(biāo)的核心是互操作性概念,即不同系統(tǒng)能夠無縫地進(jìn)行通信和共享數(shù)據(jù)。這也是 Web 服務(wù)追求的目標(biāo)。Web 服務(wù)是一
種可以用標(biāo)準(zhǔn) Internet 協(xié)議來訪問的可編程應(yīng)用邏輯;從另一個(gè)角度來說,Web 服務(wù)是有關(guān)機(jī)器間和應(yīng)用程序間透明通
信的、借助于 Web 的標(biāo)準(zhǔn)的具體實(shí)現(xiàn)。
目前,實(shí)現(xiàn)機(jī)器間消息傳遞的 Web 服務(wù)技術(shù)多種多樣,例如簡(jiǎn)單對(duì)象訪問協(xié)議 (Simple Object Access Protocol,
SOAP)、Web 服務(wù)說明語(yǔ)言 (Web Service Description Language, WSDL) 和超文本傳輸協(xié)議 (HyperText Transfer
Protocol, HTTP)。這些消息的復(fù)雜程度各不相同,既有簡(jiǎn)單的方法調(diào)用,也有復(fù)雜的訂單提交。在 Web 服務(wù)的功能中,
最一般但又較高級(jí)的功能是實(shí)現(xiàn) RPC(遠(yuǎn)程過程調(diào)用)形式的通信(通過 RPC,一臺(tái)計(jì)算機(jī)上的程序可以執(zhí)行另一臺(tái)計(jì)算
機(jī)的程序。)本文從實(shí)用的角度介紹了在使用 SOAP 進(jìn)行 RPC 形式的通信時(shí)當(dāng)前常見的互操作性問題,以后還將撰文探討
有關(guān)通過 SOAP、WSDL 以及其它協(xié)議傳送消息的問題。
什么是 SOAP?
SOAP 是 Simple Object Access Protocol(簡(jiǎn)單對(duì)象訪問協(xié)議)的縮寫。該協(xié)議的當(dāng)前版本為 1.1,其具體規(guī)范發(fā)布在下列站點(diǎn)上: www.w3.org/tr/soap(英文)。SOAP 以 XML 為基礎(chǔ),說明了機(jī)器間通信的消息傳送格式。此外,它還包括幾個(gè)可選部分,用于描述方法調(diào)用 (RPC) 和詳細(xì)說明通過 HTTP 發(fā)送 SOAP 消息的方法。(有關(guān) SOAP 和 Web 服務(wù)的詳細(xì)
背景知識(shí),請(qǐng)參見 Web 服務(wù)的平臺(tái)(英文)。)
以下是一個(gè)典型的 SOAP 請(qǐng)求(包括 HTTP 標(biāo)頭),它請(qǐng)求名為 EchoString 的 RPC 方法調(diào)用,并將一個(gè)字符串當(dāng)作參
數(shù):
POST /test/simple.asmx HTTP/1.1
Host: 131.107.72.13
Content-Type: text/xml; charset=utf-8
Content-Length: length
SOAPAction: "http://soapinterop.org/echoString"
<?xml version="1.0" encoding="utf-8"?>
<soap:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/"
xmlns:tns="http://soapinterop.org/" xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
<soap:Body soap:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">
<tns:echoString>
<inputString>string</inputString>
</tns:echoString>
</soap:Body>
</soap:Envelope>
如上所示,該請(qǐng)求將方法名編碼為 XML : <tns:echoString>,將字符串參數(shù)編碼為 <inputString>。它所代表的 C# 方法
類似于以下內(nèi)容:
public String echoString(String inputString);
以下是來自服務(wù)器的響應(yīng):
HTTP/1.1 200 OK
Content-Type: text/xml; charset=utf-8
Content-Length: length
<?xml version="1.0" encoding="utf-8"?>
<soap:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/"
xmlns:tns="http://soapinterop.org/" xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
<soap:Body soap:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">
<tns:echoStringResponse>
<Return>string</Return>
</tns:echoStringResponse>
</soap:Body>
</soap:Envelope>
有關(guān)序列化字符串?dāng)?shù)據(jù)類型以及方法調(diào)用形狀的規(guī)則在 SOAP 1.1 的第 5 節(jié)和第 7 節(jié) (www.w3.org/tr/soap(英文))
中定義。
常見的互操作性問題
當(dāng)執(zhí)行 RPC 形式的 SOAP 消息傳送時(shí),可能會(huì)因?yàn)槎喾N原因?qū)е禄ゲ僮餍詥栴}。有趣的是,許多互操作性問題都不是
SOAP 本身的問題,而是基本傳輸引擎或 XML 引擎所導(dǎo)致的互操作性問題。也就是說,互操作性問題可能是:HTTP 問題XML 問題,或SOAP 間斷性 還應(yīng)指出的是,這些規(guī)范的制定者也有考慮不周的地方,他們有時(shí)可能會(huì)模棱兩可,這樣就很難確定唯一正確的行為。傳輸問題XML Web 服務(wù)消息的核心在于發(fā)送消息的傳輸機(jī)制。當(dāng)通過 SOAP 進(jìn)行 RPC 調(diào)用時(shí),HTTP 是目前最為常用的傳輸機(jī)制。
這意味著 SOAP 堆棧之間必然存在 HTTP 互操作性問題。HTTP 互操作性問題的一個(gè)簡(jiǎn)單示例就是 SOAPAction 的使用。SOAPAction 是一種 HTTP 標(biāo)頭,它必須存在于通過 HTTP 傳送的 SOAP 消息中。此標(biāo)頭可以賦以多個(gè)不同的值,例如:
SOAPAction: "http://tempuri.org/"
SOAPAction 的值雖然可以完全為空,但必須用引號(hào)引起來:
SOAPAction:
問題就在這兒:如果服務(wù)器要求空值 SOAPAction,有些客戶端將無法滿足這一要求,因?yàn)椴⒎撬?HTTP 客戶端 API 都具有設(shè)置空 HTTP 標(biāo)頭值的方法。這種問題可能存在兩種解決方法:修正客戶端 API 和/或確保服務(wù)器不要求空值SOAPAction。通常,避免這類問題的唯一方法是確保所使用的 HTTP API 穩(wěn)定強(qiáng)壯,并且已知可以在 Web 上工作。即便如
此,這類問題仍可能出現(xiàn);要徹底消除它們,測(cè)試可能是唯一的方法。
XML 問題
這是可能存在的第二類互操作性問題,它們涉及到 XML 語(yǔ)法分析和 XSD 架構(gòu)處理。SOAP 使用 XML 和 XML 架構(gòu)作為核心,因此這兩者的互操作性是 SOAP 互操作性的基礎(chǔ)。
有一個(gè)有趣的互操作性問題示例,它同時(shí)涉及到 XML 語(yǔ)法分析和 HTTP 傳輸,并且與字節(jié)順序標(biāo)記 (Byte Order Mark,
BOM) 相關(guān)。當(dāng)通過 HTTP 發(fā)送數(shù)據(jù)時(shí),您可以在 Content-Type 標(biāo)頭中指定數(shù)據(jù)的編碼形式,如 UTF-16 或 UTF-8。也可
以通過插入一組用來指定編碼形式的字節(jié)來表示某一段 XML 的編碼形式。當(dāng)發(fā)送 UTF-16 時(shí),即使 Content-Type 標(biāo)頭中
指定了編碼形式,也仍需要 BOM 來指示是 big-endian 還是 little-endian;但對(duì)于 UTF-8,BOM 則是不必要的。例如:
HTTP/1.1 200 OK
Content-Type: text/xml; charset=utf-8
Content-Length: length
n++<?xml version="1.0" encoding="utf-8"?>
<soap:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/"
xmlns:tns="http://soapinterop.org/" xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
<soap:Body soap:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">
<tns:echoStringResponse>
<Return>string</Return>
</tns:echoStringResponse>
</soap:Body>
</soap:Envelope>
示例中的前三個(gè)字符是字節(jié)順序標(biāo)記的十六進(jìn)制代碼,用于指示編碼形式為 UTF-8,不過,您可以看到,Content-Type 也指出了這點(diǎn)。即使不需要,但是有些實(shí)現(xiàn)方案仍會(huì)為 UTF-8 發(fā)送 BOM。而其它實(shí)現(xiàn)方案有了 BOM 反而無法處理 XML。為了解決這一問題,應(yīng)避免在不需要的時(shí)候發(fā)送 BOM,并且應(yīng)正確處理 BOM。由于在處理 UTF-16 消息時(shí)需要 BOM,所以在這種情況下務(wù)必要正確處理 BOM。雖然沒有任何單一的方法可以提早解決這些問題,不過當(dāng)發(fā)現(xiàn)問題時(shí),最好的方法就是
參考描述標(biāo)準(zhǔn)的具體規(guī)范(通常在 W3C 上可以找到),然后應(yīng)用這些規(guī)范來評(píng)判遇到的問題。
SOAP 問題
現(xiàn)在,我們將討論問題的核心:SOAP 問題本身。如上所述,SOAP 的互操作性首先要求解決傳輸(通常是 HTTP)和 XML 問題。解決這兩個(gè)問題之后,再來解決 SOAP 問題。SOAP 本身的問題相對(duì)簡(jiǎn)單。它要求將消息裝入信封,并將消息的實(shí)際內(nèi)容放在正文元素中。SOAP 使標(biāo)頭等元素成為可選項(xiàng),對(duì)正文元素中可包含的內(nèi)容允許存在一定的靈活性。以下是一個(gè)簡(jiǎn)單的 SOAP 消息示例,大多數(shù)堆棧與它進(jìn)行互操作時(shí)不會(huì)存在問題:
<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
<soap:Body >
<foo />
</soap:Body>
</soap:Envelope>
雖然這個(gè)示例不是十分有趣,但是 SOAP 還提供一種對(duì)常見數(shù)據(jù)類型進(jìn)行編碼的方法(請(qǐng)參見 SOAP 規(guī)范的第 5 節(jié)),它進(jìn)一步說明了如何對(duì) RPC 方法調(diào)用進(jìn)行編碼。您可能已注意到,在前面的示例中,方法名是正文的子標(biāo)記,參數(shù)則是方法名的子標(biāo)記。即使不用這么麻煩,您也可以找到許多有趣的互操作性問題。例如,SOAP 規(guī)范規(guī)定,如果您收到mustUnderstand 屬性設(shè)置為“1”的 SOAP 標(biāo)頭,就必須理解它,否則將出錯(cuò)。但許多實(shí)現(xiàn)方案并沒有做到這點(diǎn)。以下是 mustUnderstand 標(biāo)頭的
示例:
HTTP/1.1 200 OK
Content-Type: text/xml; charset=utf-8
Content-Length: length
n++<?xml version="1.0" encoding="utf-8"?>
<soap:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/"
xmlns:tns="http://soapinterop.org/" xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
<SOAP-ENV:Header>
<Foo SOAP-ENV:mustUnderstand="1">
Hello!
</Foo>
</SOAP-ENV:Header>
<soap:Body soap:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">
<tns:echoStringResponse>
<Return>string</Return>
</tns:echoStringResponse>
</soap:Body>
</soap:Envelope>
這個(gè)示例是通過 SOAP 互操作性測(cè)試發(fā)現(xiàn)的眾多問題之一。有關(guān)現(xiàn)已發(fā)現(xiàn)的互操作性問題的更多示例,請(qǐng)參見
http://groups.yahoo.com/group/soapbuilders(英文)中的檔案。總之,為了確保 SOAP 在實(shí)現(xiàn) RPC 形式通信時(shí)的互操
作性,全世界的 SOAP 構(gòu)建者已經(jīng)做了很多工作,并取得了豐碩的成果。從 5 月 8 日到 5 月 10 日,在拉斯維加斯將舉
行 Networld+Interop 會(huì)議,到時(shí),SOAP 團(tuán)體的許多成員將在會(huì)上將充分展示這方面的成果。如果您在使用 SOAP 堆棧或
對(duì)其感興趣,歡迎惠顧這次演示會(huì)。
另外,有關(guān) XML Web 服務(wù)的許多討論和測(cè)試已經(jīng)在 http://groups.yahoo.com/group/soapbuilders(英文)、
http://www.mssoapinterop.org/(英文)和 http://www.xmethods.net/ilab/(英文)等站點(diǎn)上進(jìn)行。這些站點(diǎn)包含到許
多互操作性測(cè)試端點(diǎn)的鏈接。構(gòu)建 SOAP 堆棧的所有人員都應(yīng)該閱讀這些檔案并參與互操作性測(cè)試。
后續(xù)話題
本文簡(jiǎn)要概括了在 XML Web 服務(wù)領(lǐng)域中發(fā)現(xiàn)的一些早期互操作性問題。不過,這方面的討論并不會(huì)就此停止。除了通過 HTTP 進(jìn)行 RPC 調(diào)用之外,SOAP 還有許多更為有趣的情況需要討論。其中包括“document”形式的消息傳遞、基于 SMTP 和其它傳輸機(jī)制的 SOAP、WSDL 以及各種 SOAP 標(biāo)頭測(cè)試 - 所有這些都值得在今后的文章中進(jìn)行討論。