序:最近在研究适合项目的Web架构技术,以下技术可以直接从浏览器端访问SOAP服务器.
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@H_403_50@ 中属性
attr@H_403_50@ 的值。(请参见清单 1)
清单 1. 一个包含多个命名空间的 SOAP 信封
|
在 Mozilla 浏览器和 Firefox 浏览器中,提取 attr@H_403_50@ 属性值非常简单,如清单 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@H_403_50@、
SOAP.Envelope@H_403_50@、
SOAP.Header@H_403_50@ 和
SOAP.Body@H_403_50@)提供了构建和读取 SOAP 信封的方法,如清单 3 所示,因而处理 XML 文档对象模型的底层细节就顺利地抽象出来。
清单 3. 构建一个 SOAP 信封
|
清单 4 显示了由 清单 3 中的代码生成的 SOAP 信封。
清单 4. 构建一个 SOAP 信封
|
如果您正在创建的 SOAP 信封代表一个 RPC 样式的请求,则 SOAP.Body 元素提供了一个简便方法 set_rpc@H_403_50@(如清单 5 所示),该方法能够构造一个完整的 RPC 请求——包含一个指定的操作名称、一个指定的输入参数数组和一个 SOAP 编码样式的 URI。
清单 5. 构建一个 RPC 请求信封
|
每个参数都作为一个 JavaScript 对象结构进行传递,且可能带有以下属性:
- name。一个指定参数名称的字符串或 WS.QName 对象。必需。
- value。参数的值。如果该值不是一个简单数据类型(例如,字符串、整数或其他),则应该指定一个能将该值序列化为适当的 XML 结构的 WS.Binder。必需。
- xsitype:标识参数的 XML 模式实例类型的 WS.QName(例如,
xsi:type="int"@H_403_50@ 对应
xsitype:new WS.QName('int','http://www.w3.org/2000/10/XMLSchema')@H_403_50@)。可选。
- encodingstyle:标识参数所使用的 SOAP 编码样式的 URI。可选。
- binder:能够将参数序列化为 XML 的 WS.Binder 实现。可选。
例如,如果要指定的参数名为“abc”、XML 命名空间为“urn:foo”、xsi:type 为“int”且值为“3”,则我会使用以下代码:new Array({name:new WS.QName('abc',value:3,xsitype:new WS.QName('int','http://www.w3.org/2000/10/XMLSchema')})@H_403_50@。
一旦我为服务请求构建了 SOAP.Envelope,我就会将该 SOAP.Envelope 传递到 WS.Call 对象的 invoke@H_403_50@ 方法,以便调用该信封内编码的方法:
(new WS.Call(service_uri)).invoke(envelope,callback)@H_403_50@
另一种可选方案是手动构建 SOAP.Envelope。我会将参数 WS.QName、参数数组和编码样式传递到 WS.Call 对象的 invoke_rpc@H_403_50@ 方法,如清单 6 所示。
清单 6. 使用 WS.Call 对象调用 Web 服务
|
在调用 invoke@H_403_50@ 方法或
invoke_rpc@H_403_50@ 方法时,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@H_403_50@ 函数来调用 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 | HTTP |
关于下载方法的信息 |
学习
- 您可以参阅本文在 developerWorks 全球站点上的 英文原文。
- 您可以参阅 本系列的其他文章。
- Ajax 技术资源中心:developerWorks 上所有有关 Ajax 的问题都可以在这里找到解答。
- 面向 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 的 software group 中的 emerging Internet technologies 小组的一名设计师兼策略专家,在这个小组中,他在 Web 服务技术不断发展的体系结构和实现中起到了积极的作用。他是 Programming Web Services with SOAP(O'Reilly 和 Associates 出版)一书的合著者。您可以通过 jasnell@us.ibm.com与 James 联系。 |