两年以前,我走进了 developerWorksSoapbox ,表明我对当时新生的协议 SOAP 感兴趣。我的主要观点是,您必须喜欢 SOAP,因为它向人们熟知的 Web 基础设施增加了有用的服务。
现在 SOAP 已经成为正式的 W3C 推荐标准,我也有了实际应用它的经验。总的来说,这些经验验证了我当初的印象,即建立在 Web 基础设施上是一种好的做法。唯一的问题是 Web 还没有感知到 SOAP。这篇技巧展示了在使用 SOAP 时可能要避开的一些缺陷。
SOAP 规定如果服务器遇到错误应该返回一个 SOAP 错误码。但是服务器是为浏览器、错误配置和网络问题设计的,返回的更有可能是 HTTP 错误而不是 SOAP 错误码。
您也许会想“ 管它呢?只要正确配置服务器就行了。”但是如果说我的个人经验对您有所启发的话,您就必须考虑这一点。在 2001-2002 期间我所工作过的那些项目(即稳定的项目)中,80% 的支持请求都是基础设施问题。
多数问题都可以追踪到 Internet 连接和用户站点上的代理。有时候,似乎代理、NAT(网络地址转换)、DNS(域名服务器)和防火墙联合起来对付 Web 服务。本地网络管理员可能改变了一个参数,从而导致服务不能访问。
面对网络错误,多数 Web 服务客户报告的都是莫名其妙的胡言乱语 —— 可能是异常跟踪。如果用户遇到异常跟踪,他会打电话找 你,而不是他的网络管理员。
更糟的是,在开发期间您不大可能遇到这种问题,仅仅是因为开发服务器通常就位于本地网络中。
如果说在过去两年中构建 Web 服务得到什么教训的话,那就是发出含义明确的网络错误消息。
悲哀的是,JAX-RPC 没有什么帮助。事实上,JAX-RPC 在报告任何错误时做的工作都很少,
SOAPException
异常甚至没有返回 SOAP 错误码、字符串或者详细信息的方法。除非这种情况得到改变,否则您最大的希望就是遍历异常链,直到发现错误的更明确描述。
Apache Axis 是最流行的 SOAP 库之一,在 Java 异常链中为多数网络错误建立了专有的
AxisFault 异常。这种异常允许您检索有用的诊断信息,包括错误码和字符串。
如果这个库遇到由于代理或者服务器配置不当造成的 HTTP 错误,它就把错误码设为
{http://xml.apache.org/axis/}HTTP 。这个码是 Axis 专用的(就像名称空间 URI 所表明的那样),但总比什么也没有好。Axis 1.2 (撰写本文时处于 alpha 测试状态)更进了一步,在错误细节中返回 HTTP 错误。
如果这个库遇到由于 NAT 或者 DNS 不当配置造成的 HTTP 错误,Axis 就把错误码设为
Server.userException 。尽管
Server 类属于 SOAP 标准,但
userException 是一个扩展子码。
清单 1 中的示例代码解释 Axis 返回的
SOAPException 异常,并合情合理地打印意义明确的错误消息。清单
1 只能用于 Axis(已经用 Axis 1.1 和 1.2 alpha 版测试过),但是除非错误报告已经证明是在 JAX-RPC 中,您就只能使用这种特定于库的专用码。
清单 1. 报告网络错误
public void printSOAPException(SOAPException x)
{
Throwable cause = x.getCause();
if(cause != null && cause instanceof AxisFault)
printAxisFault((AxisFault)cause);
else if(cause != null)
System.out.println(x.getClass().getName()
+ " exception chained: "
+ x.getMessage());
else
System.out.println("SOAP exception: " + x.getMessage());
}
public void printAxisFault(AxisFault x)
{
// tested with Axis 1.1 & Axis 1.2 alpha
if(x.getFaultCode().equals(new QName("http://xml.apache.org/axis/","HTTP")))
{
Element e =
x.lookupFaultDetail(
new QName("http://xml.apache.org/axis/","HttpErrorCode"));
if(null != e)
{
e.normalize();
String httpErrorCode = e.getFirstChild().getNodeValue().trim();
if(httpErrorCode.equals("407"))
System.out.println("Proxy password incorrect");
else if(httpErrorCode.equals("502") || httpErrorCode.equals("504"))
System.out.println("Proxy cannot find the server");
else if(httpErrorCode.equals("500"))
System.out.println("Proxy or server unavailable");
else if(httpErrorCode.equals("404"))
System.out.println("No Web service (404 File Not Found)");
else
System.out.println(x.getFaultString());
}
else
System.out.println("Network error: " + x.getFaultString());
}
else if(x.getFaultCode().equals(
new QName("http://schemas.xmlsoap.org/soap/envelope/",
"Server.userException")))
System.out.println("Most likely a net error: " + x.getFaultString());
else
System.out.println("SOAP Fault: " + x.getFaultCode() + ", "
+ x.getFaultString());
} |
如果不想您的电话因为网络配置不当而响个不停,一定要让 Web 服务客户返回合理的网络错误消息。就 JAX-RPC 的目前形式而言,它还无能为力,不过就像这篇技巧所说明的那样,您可以绕过这一限制。
- 您可以参阅本文在 developerWorks 全球站点上的
英文原文.
- 参与 Benoit Marchal 的“使用 XML”专栏的
讨论论坛。
- 关于连接问题的有用观点,请参阅 Benoit Marchal 的“
Questions on HttpURLConnection and Proxies”,虽然这篇文章不是专门讨论 SOAP 的。
- 阅读 Steve Loughran 的“
The Impact of Site Finder on Web Services”,这是一篇关于 Web 服务与 Web 基础设施之间关系的讨论。
- 进一步了解 SOAP 和 Web 服务器之间的关系,请阅读 Benoit Marchal 的“
Soapbox:我为什么使用 SOAP”(
developerWorks,2001 年 2 月)。
- 从 W3C 那儿了解 SOAP 的内幕 —— 看一看它们的
XML Protocol Working Group网页。也可以看看
official primer on SOAP。
- 阅读 James Snell 介绍 SOAP 的文章“
Reflections on SOAP”(
developerWorks,2001 年 4 月)。
- 从 Apache Web 站点下载最新版本的
Axis。
- Dan Gisolfi 的“
Web 服务设计师”(
developerWorks,2001 年 4 月),提供了关于 Web 服务体系结构的有用信息。
-
HTTP 1.1 RFC的第 10 部分列出了状态码,您可以看看其中的一些,尤其是和代理与网关有关的那些。
- 可以在
developerWorks
XML 专区找到更多的 XML 资源。关于最新 XML 技巧的完整列表,请查看
实用技巧。
- 订阅每周一次的
developerWorks
Web 服务/XML 技巧时事通讯。
- 在
developerWorks
Developer Bookstore上可以购买 Benoit Marchal 所著的书
Applied XML Solutions
。
- 了解如何才能成为一名
IBM 认证的 XML 及相关技术的开发人员。

Benoit Marchal 是一位比利时籍顾问。他是 XML by Example, Second Edition 以及其他几本 XML 书籍的作者。他主要从事 XML、Java 技术和电子商务方面的工作。关于本主题的更多信息,请参阅 www.marchal.com。可以通过 bmarchal@pineapplesoft.com和他联系。