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

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

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

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