关于AxisFault的说明

关于AxisFault的说明

关于AxisFault的说明

最新推荐文章于 2021-03-04 13:14:10 发布

iteye_18357

最新推荐文章于 2021-03-04 13:14:10 发布

阅读量2.4k

收藏

1

点赞数

文章标签:

SOAP

Apache

Tomcat

XML

Web

本文探讨了在Axis2 WebService中如何处理SOAP Fault,包括构造AxisFault的方法及其在不同SOAP版本间的转换问题。

摘要生成于

C知道

,由 DeepSeek-R1 满血版支持,

前往体验 >

一般说来,不可避免的Web Service的服务中也会出现异常,举个简单的例子,一个服务接受一个SOAP请求消息,获取有效负载后,进行一个数据库更新操作,而在更新操作过程中发生了SQLException,这个时候就需要告诉客户端(调用Web Service)出现异常了,Axis2将异常封装成为一个AxisFault进行抛出。任何类型的异常Axis2都会对其进行封装,而不管该异常是运行时异常,还是用户自定义异常。

下面是对AxisFault API的一点介绍:

public class AxisFault extends RemoteException

An exception which maps cleanly to a SOAP fault. This is a base class for exceptions which are mapped to faults.

See Also:

SOAP1.2 specification,

SOAP1.1 Faults

SOAP faults contain

1.

A fault string

2.

A fault code

3.

A fault actor

4.

Fault details; an xml tree of fault specific elements

(其中红色的部分为一个AxisFault构造时所必须的部分)

As SOAP1.2 faults are a superset of SOAP1.1 faults, this type holds soap1.2 fault information. When a SOAP1.1 fault is created, spurious information can be discarded. Mapping

SOAP1.2 SOAP1.1

node faultactor

reason(0).text faultstring

faultcode.value faultcode

faultcode.subcode (discarded)

detail detail

role (discarded)

构造函数之一为:

AxisFault

(org.apache.axiom.soap.SOAPFaultCode soapFaultCode, org.apache.axiom.soap.SOAPFaultReason soapFaultReason, org.apache.axiom.soap.SOAPFaultNode soapFaultNode, org.apache.axiom.soap.SOAPFaultRole soapFaultRole, org.apache.axiom.soap.SOAPFaultDetail soapFaultDetail)

由于SOAP 1.1的SOAPFault和SOAP 1.2的SOAPFault的结构不相同,从而导致了如果以1.2的方式构造的SOAPFault不能够被1.1版本的SOAPFault所理解,从而导致异常,异常的内容经常为如下消息:

org.apache.axiom.soap.SOAPProcessingException: Expecting SOAP 1.1 implementation

of SOAP Fault Code. But received some other implementation

一般情况下,SOAPFault是通过SOAPFactory这个工厂类构造的,而SOAP11Factory和SOAP12Factory均继承SOAPFactory,从而对应与两个不同的SOAP协议版本。

可以将SOAP1.1的SOAPFault与SOAP1.2的SOAPFault进行转换,但是比较麻烦。

下面以一个实际的例子来说明有关SOAPFault的一些内容:

1.

建立工程TestFault,如下图所示目录结构:

其中类库使用的是从http://ws.apache.org/axis2下载的最新版本的axis2软件中的类库(笔者写这篇文章时的最新axis2版本为1.1.1)。下载后解压缩,将解压缩后的目录中的lib文件夹下所有的jar文件拷贝到${eclipse.home}/workspace/TestFault/src下,目录结构可能与此不同,只需要将这些jar文件加入到TestFault工程的构建路径中即可。

编写服务器端和客户端的类:

FaultService.java

package l.z.z;

import javax.xml.namespace.QName;

import org.apache.axiom.om.OMAbstractFactory;

import org.apache.axiom.om.OMElement;

import org.apache.axiom.soap.SOAP12Constants;

import org.apache.axiom.soap.SOAPBody;

import org.apache.axiom.soap.SOAPEnvelope;

import org.apache.axiom.soap.SOAPFactory;

import org.apache.axiom.soap.SOAPFault;

import org.apache.axiom.soap.SOAPFaultCode;

import org.apache.axiom.soap.SOAPFaultReason;

import org.apache.axiom.soap.SOAPFaultText;

import org.apache.axiom.soap.SOAPFaultValue;

import org.apache.axis2.AxisFault;

public class FaultService {

public OMElement testFault(OMElement soap) throws AxisFault {

if (soap.getLocalName().equals("Satan")) {

throw getAxisFault("Satan");

}

throw getAxisFault("God");

}

public AxisFault getAxisFault(String message) {

SOAPFactory factory = OMAbstractFactory.getSOAP12Factory();

SOAPEnvelope envelope = factory.createSOAPEnvelope();

SOAPBody body = factory.createSOAPBody(envelope);

SOAPFault soapFault = factory.createSOAPFault(body);

SOAPFaultCode faultCode = factory.createSOAPFaultCode(soapFault);

SOAPFaultReason faultReason =

factory.createSOAPFaultReason(soapFault);

SOAPFaultValue faultValue = factory.createSOAPFaultValue(faultCode);

SOAPFaultText reasonText =

factory.createSOAPFaultText(faultReason);

QName value =

new QName(SOAP12Constants.SOAP_ENVELOPE_NAMESPACE_URI,

SOAP12Constants.SOAP_FAULT_VALUE_SENDER,

SOAP12Constants.SOAP_DEFAULT_NAMESPACE_PREFIX);

faultValue.setText(value);

reasonText.setText(message);

AxisFault axisFault = new AxisFault(soapFault.getCode(), soapFault

.getReason(), null, null, null);

return axisFault;

}

}

TestFaultService.java

package l.z.z.test;

import java.io.FileInputStream;

import java.io.FileNotFoundException;

import javax.xml.stream.FactoryConfigurationError;

import javax.xml.stream.XMLInputFactory;

import javax.xml.stream.XMLStreamException;

import javax.xml.stream.XMLStreamReader;

import org.apache.axiom.om.OMElement;

import org.apache.axiom.om.impl.builder.StAXOMBuilder;

import org.apache.axis2.AxisFault;

import org.apache.axis2.addressing.EndpointReference;

import org.apache.axis2.client.Options;

import org.apache.axis2.client.ServiceClient;

public class TestFaultService {

private static EndpointReference targetEPR = new EndpointReference(

"http://localhost/axis2/services/FaultService");

public static void main(String[] args) throws FileNotFoundException,

FactoryConfigurationError, XMLStreamException {

OMElement requestSoapMessage =

getSoapRequestMessage("sample/Satan.xml");

Options options = new Options();

options.setAction("urn:testFault");

options.setTo(targetEPR);

ServiceClient sender = null;

try {

sender = new ServiceClient();

sender.setOptions(options);

sender.sendReceive(requestSoapMessage);

} catch (AxisFault e) {

System.out.println(e.getMessage());

}

}

public static OMElement getSoapRequestMessage(String filePath)

throws FileNotFoundException, XMLStreamException,

FactoryConfigurationError {

XMLStreamReader reader = XMLInputFactory.newInstance()

.createXMLStreamReader(new FileInputStream(filePath));

StAXOMBuilder builder = new StAXOMBuilder(reader);

OMElement requestMessage = builder.getDocumentElement();

return requestMessage;

}

}

然后编写services.xml文件,内容如下:

<

serviceGroup

>

<

service

name

=

"FaultService"

>

<

description

>

This is the service for revoking certificate.

description

>

<

parameter

name

=

"ServiceClass"

locked

=

"false"

>

l.z.z.FaultService

parameter

>

<

operation

name

=

"testFault"

>

<

messageReceiver

class

=

"org.apache.axis2.receivers.RawXMLINOutMessageReceiver"

/>

<

actionMapping

>

urn:testFault

actionMapping

>

operation

>

service

>

serviceGroup

>

由于本文假设读者已经有axis2开发Web Service的基础,所以对于以上类及配置文件不做解释,敬请原谅。

打包成FaultService.aar文件,文件中包含内容如下:

FaultService.aar

---l

---z

---z

---FaultService.class

---META-INF

---MANIFEST.MF

---services.xml

将该aar包放置到${TOMCAT_HOME}\webapps\axis2\WEB-INF\services目录下。

启动Tomcat,进入

http://localhost:{port}/axis2

然后选择Services,察看服务是否部署成功,如果已经部署成功,进入下一步骤,否则,请重新检查以上各个步骤。成功后应该如下图所示:

2执行TestFaultService类,可以看到错误消息如下:

(类代码参照上面列出的类)

Transport error 500 . Error Message is Apache Tomcat/5.5.17 - Error report

HTTP Status 500 -


type Exception report

message

description The server encountered an internal error () that prevented it from fulfilling this request.

exception

org.apache.axiom.soap.SOAPProcessingException: Expecting SOAP 1.1 implementation of SOAP Fault Code. But received some other implementation

org.apache.axiom.soap.impl.llom.soap11.SOAP11FaultImpl.setCode(SOAP11FaultImpl.java:81)

org.apache.axis2.engine.AxisEngine.extractFaultInformationFromMessageContext(

AxisEngine.java:330

)

org.apache.axis2.engine.AxisEngine.createFaultMessageContext(

AxisEngine.java:249

)

org.apache.axis2.transport.http.AxisServlet.handleFault(

AxisServlet.java:317

)

org.apache.axis2.transport.http.AxisServlet.doPost(

AxisServlet.java:277

)

javax.servlet.http.HttpServlet.service(

HttpServlet.java:709

)

javax.servlet.http.HttpServlet.service(

HttpServlet.java:802

)

其中红色的部分是问题的关键,该部分意思是说,客户端期望获得的是一个SOAP 1.1的SOAP Fault Code,但是,我们实际提供的却是一个1.2的实现,所以客户端处理不了,就抛出了异常,而实际出异常的地方那个是红色字体下面的蓝色字体:

SOAP11FaultImpl.setCode时,由于是一个SOAP1.2的SOAP Fault Code,所以不能够处理,只能跑出异常。

而通过使用SOAPMonitor观察到的传入SOAP请求消息是:

注意,Axis2自动的将传入的消息加上一层封装,在传输过程中(没有到达Web Service方法testFault之前)是以这个形式传输的,而Axis2使用的默认的SOAP版本是1.1,所以,不管在FaultService类中构造的AxisFault是SOAP11还是SOAP12,最后都会试图将其转换为SOAP11的格式,而一旦此时出现版本冲突,就会发生异常。

AxisFault还没有返回到客户端,就已经发生了异常(上图中SOAPResponse内容为空)。

解决办法一:

将SOAP12的Fault转换为SOAP11的Fault,这样可以传出SOAP11构造的SOAPFault,但是,名称却和SOAP12一致(比如服务器端异常并不是使用SOAP11的”Server”,而是SOAP12的”Receiver”)。这种办法虽然可以实行,但是一旦客户端是SOAP12怎么办,缺少共通性。

解决办法二:

在构造SOAPFault时进行判断,如果客户端使用的是SOAP12,则使用SOAP12Factory来构造,否则使用SOAP11来构造。

这时,就需要在客户端设置使用的SOAP版本,通过一下方法:

Options

options =

new

Options

();

options.setSoapVersionURI(SOAP12Constants.SOAP_ENVELOPE_NAMESPACE_URI);

这样,就可以设置在传输过程中使用的SOAP封装是SOAP12版本。

这时,通过SOAPMonitor观察到的SOAP请求和响应的消息为:

只所以会有这样的不同是因为通过使用

options.setSoapVersionURI(SOAP12Constants.SOAP_ENVELOPE_NAMESPACE_URI);

设置了将被使用的SOAP的版本。

由于有些客户端可能使用的是不支持SOAP12版本的SOAP协议,所以,有时候需要将SOAP11进行到SOAP12的装换。