使用 AJAX 調(diào)用 SOAP Web 服務(wù),第 1 部分: 構(gòu)建 Web 服務(wù)客戶機(jī)
級(jí)別: 中級(jí)
James Snell, 軟件工程師, IBM
2006 年 1 月 16 日
本文介紹如何使用異步 JavaScript 和 XML (Asynchronous JavaScript and XML, AJAX) 設(shè)計(jì)模式來(lái)實(shí)現(xiàn)基于 Web 瀏覽器的 SOAP Web 服務(wù)客戶機(jī)。
本文是一篇短的系列文章的第 1 部分,演示了如何使用針對(duì) Web 應(yīng)用程序的 AJAX 設(shè)計(jì)模式來(lái)實(shí)現(xiàn)跨平臺(tái)的基于 JavaScript 的 SOAP Web 服務(wù)客戶機(jī)。
AJAX 已普遍用于許多知名的 Web 應(yīng)用程序服務(wù),例如 GMail、Google Maps、Flickr 和 Odeo.com。通過(guò)使用異步 XML 消息傳遞,AJAX 為 Web 開發(fā)人員提供了一種擴(kuò)展其 Web 應(yīng)用程序價(jià)值和功能的途徑。這里介紹的 Web Services JavaScript Library 擴(kuò)展了該基礎(chǔ)機(jī)制,其通過(guò)引入對(duì)調(diào)用基于 SOAP 的 Web 服務(wù)的支持來(lái)增強(qiáng) AJAX 設(shè)計(jì)模式。
從 Web 瀏覽器中調(diào)用 SOAP Web 服務(wù)可能會(huì)比較麻煩,這是因?yàn)榇蠖鄶?shù)流行的 Web 瀏覽器在生成和處理 XML 方面都略有不同。所有瀏覽器都一致實(shí)現(xiàn)且用于 XML 處理的標(biāo)準(zhǔn) API 或功能少之又少。
瀏 覽器實(shí)現(xiàn)人員一致支持的機(jī)制之一是 XMLHttpRequest API,它是 AJAX 設(shè)計(jì)模式的核心。developerWorks 網(wǎng)站最近發(fā)布的另一篇由 Philip McCarthy 撰寫的的文章詳細(xì)介紹了該 API。XMLHttpRequest 是一個(gè)用于執(zhí)行異步 HTTP 請(qǐng)求的 JavaScript 對(duì)象。Philip McCarthy 在其文章中描述了一個(gè)順序圖(請(qǐng)參見圖 1),此圖對(duì)于理解 XMLHttpRequest 對(duì)象如何支持 AJAX 設(shè)計(jì)非常有幫助(請(qǐng)參閱參考資料,以獲得指向全文的鏈接)。
圖 1. Philip McCarthy 的 AJAX 順序圖

從 此圖中,您可以清楚地看到 XMLHttpRequest 對(duì)象是如何工作的。一些運(yùn)行在 Web 瀏覽器內(nèi)的 JavaScript 創(chuàng)建了一個(gè) XMLHttpRequest 實(shí)例和一個(gè)用于異步回調(diào)的函數(shù)。然后,該腳本使用 XMLHttpRequest 對(duì)象對(duì)服務(wù)器執(zhí)行 HTTP 操作。在接收到響應(yīng)后,調(diào)用回調(diào)函數(shù)。在該回調(diào)函數(shù)內(nèi),可能處理返回的數(shù)據(jù)。如果返回的數(shù)據(jù)碰巧是 XML,則 XMLHttpRequest 對(duì)象將自動(dòng)使用瀏覽器中內(nèi)置的 XML 處理機(jī)制來(lái)解析該數(shù)據(jù)。
遺憾的是,使用 AJAX 方法的主要難題在于 XMLHttpRequest 對(duì)象自動(dòng)解析 XML 的詳細(xì)過(guò)程。例如,假設(shè)我正在請(qǐng)求的數(shù)據(jù)是一個(gè) SOAP 信封,其包含來(lái)自許多不同 XML 命名空間的元素,并且我希望提取 yetAnotherElement
中屬性 attr
的值。(請(qǐng)參見清單 1)
清單 1. 一個(gè)包含多個(gè)命名空間的 SOAP 信封
|
在 Mozilla 瀏覽器和 Firefox 瀏覽器中,提取 attr
屬性值非常簡(jiǎn)單,如清單 2所示。
清單 2. 在 Mozilla 和 Firefox 中檢索 attr 屬性值的方法不能運(yùn)用在 Internet Explorer 中
|
![]() |
|
遺 憾的是,以上代碼無(wú)法在 Internet Explorer Version 6 中運(yùn)行,因?yàn)樵摓g覽器不僅沒(méi)有實(shí)現(xiàn) getElementsByTagNameNS 功能,而且事實(shí)上還使用了一種很糟糕的方法——將 XML 命名空間的前綴作為其元素和屬性名稱的一部分來(lái)對(duì)待。
Internet Explorer 缺少對(duì) XML 命名空間的支持,這使得它很難處理命名空間密集的 XML 格式,例如采用獨(dú)立于瀏覽器的方式的 SOAP。即使要執(zhí)行一些像提取結(jié)果中的屬性值這樣簡(jiǎn)單的操作,您也必須編寫能夠在多個(gè)瀏覽器中實(shí)現(xiàn)一致預(yù)期行為的特殊代碼。幸運(yùn)的是,這種特殊代碼可以 封裝并重用。
為了從 Web 瀏覽器中調(diào)用 Web 服務(wù),并可靠地處理 SOAP 消息,您需要首先了解一些安全問(wèn)題(請(qǐng)參見側(cè)欄“關(guān)于安全性”)。此外,您還需要編寫一個(gè) JavaScript 腳本庫(kù)(圖 2),以便將底層瀏覽器 XML 實(shí)現(xiàn)中的不一致情況抽象出來(lái),從而使您能夠直接處理 Web 服務(wù)數(shù)據(jù)。
圖 2. 在使用 Web Services JavaScript Library 的 Web 瀏覽器中通過(guò) Javascript 調(diào)用 Web 服務(wù)

圖 2 中的 Web Services JavaScript Library (ws.js) 是一組 JavaScript 對(duì)象和實(shí)用功能,它們?yōu)榛?SOAP 1.1 的 Web 服務(wù)提供了基本的支持。Ws.js 定義了下列對(duì)象:
- WS.Call:一個(gè)包裝了 XMLHttpRequest 的 Web 服務(wù)客戶機(jī)
- WS.QName:XML 限定名實(shí)現(xiàn)
- WS.Binder:自定義 XML 序列化器/反序列化器的基礎(chǔ)
- WS.Handler:請(qǐng)求/響應(yīng)處理程序的基礎(chǔ)
- SOAP.Element:包裝了 XML DOM 的基本 SOAP 元素
- SOAP.Envelope:SOAP Envelope 對(duì)象擴(kuò)展了 SOAP.Element
- SOAP.Header:SOAP Header 對(duì)象擴(kuò)展了 SOAP.Element
- SOAP.Body:SOAP Body 對(duì)象擴(kuò)展了 SOAP.Element
- XML:用于處理 XML 的跨平臺(tái)實(shí)用方法
ws.js 的核心是 WS.Call 對(duì)象,該對(duì)象提供了調(diào)用 Web 服務(wù)的方法。WS.Call 主要負(fù)責(zé)與 XMLHttpRequest 對(duì)象進(jìn)行交互,并處理 SOAP 響應(yīng)。
WS.Call 對(duì)象公開了以下三個(gè)方法:
- add_handler。向處理鏈添加請(qǐng)求/響應(yīng)處理程序。處理程序?qū)ο笤谡{(diào)用 Web 服務(wù)的前后被調(diào)用,以支持可擴(kuò)展的預(yù)調(diào)用處理和后調(diào)用處理。
- invoke。將指定的 SOAP.Envelope 對(duì)象發(fā)送給 Web 服務(wù),然后在接收到響應(yīng)后調(diào)用回調(diào)函數(shù)。當(dāng)調(diào)用使用文本 XML 編碼的文檔樣式的 Web 服務(wù)時(shí),請(qǐng)使用此方法。
- invoke_rpc。創(chuàng)建一個(gè)封裝 RPC 樣式請(qǐng)求的 SOAP.Envelope,并將其發(fā)送到 Web 服務(wù)。當(dāng)接收到響應(yīng)時(shí),調(diào)用回調(diào)函數(shù)。
在 通常情況下,WS.Call 對(duì)象只不過(guò)是位于 XMLHttpRequest 對(duì)象頂層的瘦包裝器 (thin wrapper),該包裝器能夠執(zhí)行許多簡(jiǎn)化處理的操作。這些操作包括設(shè)置 SOAP 1.1 規(guī)范要求的 SOAPAction HTTP Header。
![]() ![]() |
![]()
|
Web services JavaScript Library 提供的 API 非常簡(jiǎn)單。
SOAP.* 對(duì)象(SOAP.Element
、SOAP.Envelope
、SOAP.Header
和 SOAP.Body
)提供了構(gòu)建和讀取 SOAP 信封的方法,如清單 3 所示,因而處理 XML 文檔對(duì)象模型的底層細(xì)節(jié)就順利地抽象出來(lái)。
清單 3. 構(gòu)建一個(gè) SOAP 信封
|
清單 4 顯示了由 清單 3 中的代碼生成的 SOAP 信封。
清單 4. 構(gòu)建一個(gè) SOAP 信封
|
如果您正在創(chuàng)建的 SOAP 信封代表一個(gè) RPC 樣式的請(qǐng)求,則 SOAP.Body 元素提供了一個(gè)簡(jiǎn)便方法 set_rpc
(如清單 5 所示),該方法能夠構(gòu)造一個(gè)完整的 RPC 請(qǐng)求——包含一個(gè)指定的操作名稱、一個(gè)指定的輸入?yún)?shù)數(shù)組和一個(gè) SOAP 編碼樣式的 URI。
清單 5. 構(gòu)建一個(gè) RPC 請(qǐng)求信封
|
每個(gè)參數(shù)都作為一個(gè) JavaScript 對(duì)象結(jié)構(gòu)進(jìn)行傳遞,且可能帶有以下屬性:
- name。一個(gè)指定參數(shù)名稱的字符串或 WS.QName 對(duì)象。必需。
- value。參數(shù)的值。如果該值不是一個(gè)簡(jiǎn)單數(shù)據(jù)類型(例如,字符串、整數(shù)或其他),則應(yīng)該指定一個(gè)能將該值序列化為適當(dāng)?shù)?XML 結(jié)構(gòu)的 WS.Binder。必需。
-
xsitype:標(biāo)識(shí)參數(shù)的 XML 模式實(shí)例類型的 WS.QName(例如,
xsi:type="int"
對(duì)應(yīng)xsitype:new WS.QName('int','http://www.w3.org/2000/10/XMLSchema')
)。可選。 - encodingstyle:標(biāo)識(shí)參數(shù)所使用的 SOAP 編碼樣式的 URI。可選。
- binder:能夠?qū)?shù)序列化為 XML 的 WS.Binder 實(shí)現(xiàn)。可選。
例如,如果要指定的參數(shù)名為“abc”、XML 命名空間為“urn:foo”、xsi:type 為“int”且值為“3”,則我會(huì)使用以下代碼:new Array({name:new WS.QName('abc','urn:foo'), value:3,
xsitype:new WS.QName('int','http://www.w3.org/2000/10/XMLSchema')})
。
一旦我為服務(wù)請(qǐng)求構(gòu)建了 SOAP.Envelope,我就會(huì)將該 SOAP.Envelope 傳遞到 WS.Call 對(duì)象的 invoke
方法,以便調(diào)用該信封內(nèi)編碼的方法:
(new WS.Call(service_uri)).invoke(envelope, callback)
另一種可選方案是手動(dòng)構(gòu)建 SOAP.Envelope。我會(huì)將參數(shù) WS.QName、參數(shù)數(shù)組和編碼樣式傳遞到
WS.Call 對(duì)象的 invoke_rpc
方法,如清單 6 所示。
清單 6. 使用 WS.Call 對(duì)象調(diào)用 Web 服務(wù)
|
在調(diào)用 invoke
方法或
invoke_rpc
方法時(shí),WS.Call 對(duì)象會(huì)創(chuàng)建一個(gè)基本的 XMLHttpRequest 對(duì)象,用包含 SOAP 信封的 XML 元素進(jìn)行傳遞,并接收和解析響應(yīng),然后調(diào)用提供的回調(diào)函數(shù)。
為了能夠擴(kuò)展 SOAP 消息的預(yù)處理和后處理,WS.Call 對(duì)象允許您注冊(cè)一組 WS.Handler 對(duì)象,如清單 7 所示。對(duì)于調(diào)用周期內(nèi)的每個(gè)請(qǐng)求、每個(gè)響應(yīng)和每個(gè)錯(cuò)誤,都將調(diào)用這些對(duì)象。可以通過(guò)擴(kuò)展 WS.Handler JavaScript 對(duì)象來(lái)實(shí)現(xiàn)新的處理程序。
清單 7. 創(chuàng)建和注冊(cè)響應(yīng)/響應(yīng)處理程序
|
處理程序?qū)Σ迦牖蛱崛≌趥鬟f的 SOAP 信封中的信息最有用。例如,您可以設(shè)想一個(gè)處理程序自動(dòng)向 SOAP Envelope 的 Header 插入適當(dāng)?shù)?Web 服務(wù)尋址 (Web Services Addressing) 元素,如清單 8 中的示例所示。
清單 8. 一個(gè)將 Web 服務(wù)尋址操作 Header 添加到請(qǐng)求中的處理程序示例
|
WS.Binder 對(duì)象(清單 9)執(zhí)行 SOAP.Element 對(duì)象的自定義序列化和反序列化。WS.Binder 的實(shí)現(xiàn)必須提供以下兩個(gè)方法:
- to_soap_element。將 JavaScript 對(duì)象序列化為 SOAP.Element。傳入的第一個(gè)參數(shù)是要序列化的值。第二個(gè)參數(shù)是 SOAP.Element,必須將要序列化的值序列化為 SOAP.Element。該方法不返回任何值。
- to_value_object。將 SOAP.Element 反序列化為 JavaScript 對(duì)象。該方法必須返回反序列化的值對(duì)象。
清單 9. WS.Binding 實(shí)現(xiàn)示例
|
![]() ![]() |
![]()
|
我已經(jīng)提供了一個(gè)示例項(xiàng)目來(lái)闡釋 Web Services JavaScript Library 的基本功能。該演示所使用的 Web 服務(wù)(如清單 10 所示)已經(jīng)在 WebSphere Application Server 中進(jìn)行了實(shí)現(xiàn),并提供了簡(jiǎn)單的 Hello World 功能。
清單 10. 一個(gè)簡(jiǎn)單的基于 Java 的“Hello World”Web 服務(wù)
|
在實(shí)現(xiàn)了該服務(wù)并將其部署到 WebSphere Application Server 后,該服務(wù)(清單 11)的 WSDL 描述定義了您需要傳遞的 SOAP 消息(用于調(diào)用 Hello World 服務(wù))。
清單 11. HelloWorld.wsdl 的代碼片段
|
通過(guò)使用 Web Services JavaScript Library,您可以實(shí)現(xiàn)一個(gè)調(diào)用 Hello World 服務(wù)的方法,如清單 12所示。
清單 12. 使用 WS.Call 調(diào)用 HelloWorld 服務(wù)
|
然后,您可以在我們的 Web 應(yīng)用程序中的任意位置通過(guò)調(diào)用 sayHello
函數(shù)來(lái)調(diào)用 Hello World 服務(wù)。請(qǐng)參見清單 13。
清單 13. 調(diào)用 sayHello 函數(shù)
|
調(diào)用成功后的結(jié)果如圖 3 所示。在 Mozilla、Firefox 和 Internet Explorer 中運(yùn)行該示例應(yīng)該會(huì)得到相同的結(jié)果。
圖 3. Firefox 中的 Hello World 示例

![]() ![]() |
![]()
|
使 用 Web Services JavaScript Library,可以采用簡(jiǎn)單的獨(dú)立于瀏覽器的方式將基本的 SOAP Web 服務(wù)合并到 Web 應(yīng)用程序中。在本系列的下一個(gè)部分中,您不僅可以探討如何使用該庫(kù)來(lái)調(diào)用更多基于 Web 服務(wù)資源框架 (WS-Resource Framework ) 系列規(guī)范的高級(jí) Web 服務(wù),而且還可以了解擴(kuò)展該 Web 服務(wù)功能并將其集成到 Web 應(yīng)用程序中的方法。
![]() ![]() |
![]()
|
描述 | 名字 | 大小 | 下載方法 |
---|---|---|---|
Sample project | ws-wsajaxcode.zip | 19 KB | ?FTP |
![]() |
||||
![]() |
關(guān)于下載方法的信息 |
![]() |
![]() |
Get Adobe? Reader? |
![]() ![]() |
![]()
|
學(xué)習(xí)
- 您可以參閱本文在 developerWorks 全球站點(diǎn)上的 英文原文。
-
面向 Java 開發(fā)人員的 Ajax: 構(gòu)建動(dòng)態(tài)的 Java 應(yīng)用程序——Philip McCarthy 在本文中向 Java 開發(fā)人員介紹了 Ajax(developerWorks,2005 年 9 月)。
-
JavaScript
Framework——了解 Web Services JavaScript Library 所基于的原型框架。
-
XMLHttpRequest API——從 XUL Planet 網(wǎng)站上了解更多關(guān)于 XMLHttpRequest API 的內(nèi)容。
-
XMLHttpRequest API -- Learn more about it from the XUL Planet Web site.
-
Exploit the Document Object Model to create enhanced Web applications
——了解更多關(guān)于 Microsoft Internet Explorer 6.0 所使用的 XML 文檔對(duì)象模型的內(nèi)容(developerWorks,2004 年 2 月)。
-
Mozilla Web services——了解更多關(guān)于
Mozilla/Firefox 內(nèi)置 Web 服務(wù)支持的內(nèi)容。
獲得產(chǎn)品和技術(shù)
- 從 developerWorks 下載 WebSphere Application Server 的免費(fèi)試用版。
討論
-
通過(guò)參與 developerWorks 博客加入 developerWorks 社區(qū)。
![]() ![]() |
![]()
|
![]() |
||
|
![]() |
James Snell 是 IBM Emerging Technologies Toolkit 團(tuán)隊(duì)的成員。在過(guò)去幾年里,他一直致力于新興 Web 服務(wù)技術(shù)和標(biāo)準(zhǔn)的研究,并且還參與了 Atom 1.0 規(guī)范的制定。他現(xiàn)在維護(hù)著一個(gè)專注于新興技術(shù)的博客 http://www.ibm.com/developerworks/blogs/dw_blog.jspa?blog=351。 |
posted on 2006-03-19 16:00 Vincent.Chen 閱讀(322) 評(píng)論(0) 編輯 收藏 所屬分類: AJAX