• 关于AxisFault的说明(转)


    一般说来,不可避免的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:
    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 <html><head><title>Apache Tomcat/5.5.17 - Error report</title><style><!--H1 {color:white;background-color:#525D76;font-size:22px;} H2 {color:white;background-color:#525D76;font-size:16px;} H3 {color:white;background-color:#525D76;font-size:14px;} BODY {color:black;background-color:white;} B {color:white;background-color:#525D76;} P {background:white;color:black;font-size:12px;}A {color : black;}A.name {color : black;}HR {color : #525D76;}--></style> </head><body><h1>HTTP Status 500 - </h1><HR size="1" noshade="noshade"><p><b>type</b> Exception report</p><p><b>message</b> <u></u></p><p><b>description</b> <u>The server encountered an internal error () that prevented it from fulfilling this request.</u></p><p><b>exception</b> <pre>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的装换。
  • 相关阅读:
    php多态
    ssl certificate problem: self signed certificate in certificate chain
    test plugin
    open specific port on ubuntu
    junit vs testng
    jersey rest service
    toast master
    use curl to test java webservice
    update folder access
    elk
  • 原文地址:https://www.cnblogs.com/huqingyu/p/1144036.html
Copyright © 2020-2023  润新知