9

我使用 AXIS2 创建的 ADB 存根访问 SOAP 服务。我想记录服务返回的任何 Axis Fault 的原始 XML 响应。我可以将这些错误捕获为“ServiceError”。但是,我没有找到检索原始 XML 的方法(请参见下面的示例)。

我找到了一种使用 getOMElement 访问原始 XML 请求/响应以进行常规处理的方法(请参见下面的示例)。但是,这不适用于故障。

如何使用 ADB 存根获取原始 XML 错误?

示例 Java 代码:

    public void testRequest(String URL) throws AxisFault {
        MyServiceStub myservice = new MyServiceStub(URL);
        MyRequest req = new MyRequest();
        try {
            TypeMyFunctionResponse response = myservice.myFunction(req);

            // logging full soap response
            System.out.println("SOAP Response: "
                    + response.getOMElement(null,
                            OMAbstractFactory.getOMFactory())
                            .toStringWithConsume());
        } catch (RemoteException e) {
            //...
        } catch (ServiceError e) {
            // how to get the raw xml?
        }
    }

示例故障响应,我想获取并记录:

<?xml version='1.0' encoding='UTF-8'?>
<soapenv:Envelope xmlns:soapenv="http://www.w3.org/2003/05/soap-envelope">
    <soapenv:Body>
        <soapenv:Fault>
            <soapenv:Code>
                <soapenv:Value>soapenv:Receiver</soapenv:Value>
            </soapenv:Code>
            <soapenv:Reason>
                <soapenv:Text xml:lang="en-US">service error</soapenv:Text>
            </soapenv:Reason>
            <soapenv:Detail>
                <ns1:error xmlns:ns1="http://www.somehost.com/webservices/someservice">
                    <ns1:code>500</ns1:code>
                    <ns1:messageText>some fault message</ns1:messageText>
                </ns1:error>
            </soapenv:Detail>
        </soapenv:Fault>
    </soapenv:Body>
</soapenv:Envelope>
4

5 回答 5

9

以下是您可能正在寻找的内容,yourStub是您通过 wsdl2java 生成的内容,并在您提出请求后使用以下行。消息设置为lastOperation并在您进行实际呼叫时发送:

request = yourStub._getServiceClient().getLastOperationContext().getMessageContext("Out")
              .getEnvelope().toString());

response = yourStub._getServiceClient().getLastOperationContext().getMessageContext("In")
              .getEnvelope().toString());

希望这会有所帮助。

于 2014-01-03T22:27:11.107 回答
5

虽然这个问题已经得到了很好的回答,但我需要更早地这样做,并且很难找到适合我的限制的合适答案,所以我为后代添加了我自己的答案。

对于最近运行 JDK 1.4 的项目,我需要使用 Axis 2 版本 1.4.1 执行此操作,根据我所读到的内容,JAX-WS 存根不支持该项目。我最终保留了 ADB 存根,同时通过使用我自己的构建器类包装 SoapBuilder、复制输入流并将副本传递给 SoapBuilder 来捕获输入:

public class SOAPBuilderWrapper implements Builder {
    private String lastResponse;

    private SOAPBuilder builder = new SOAPBuilder();

    private static final int BUFFER_SIZE = 8192;

    public OMElement processDocument(InputStream inputStream,
            String contentType, MessageContext messageContext) throws AxisFault {
        ByteArrayOutputStream copiedStream = new ByteArrayOutputStream();
        try {
            byte[] buffer = new byte[BUFFER_SIZE];
            int bytesRead = inputStream.read(buffer);
            while (bytesRead > -1) {
                copiedStream.write(buffer, 0, bytesRead);
                bytesRead = inputStream.read(buffer);
            }
            lastResponse = copiedStream.toString();

        } catch (IOException e) {
            throw new AxisFault("Can't read from input stream", e);
        }
        return builder.processDocument(
                new ByteArrayInputStream(copiedStream.toByteArray()),
                contentType, messageContext);
    }

    public String getLastResponse() {
        return lastResponse;
    }
}

由于各种原因,使用 axis2.xml 进行配置是有问题的,因此以编程方式添加了包装器,其中包含以下内容:

SoapBuilderWrapper responseCaptor = new SoapBuilderWrapper();
AxisConfiguration axisConfig = stub._getServiceClient().getAxisConfiguration();
axisConfig.addMessageBuilder("application/soap+xml", responseCaptor);
axisConfig.addMessageBuilder("text/xml", responseCaptor);

这允许在调用服务后使用 responseCaptor.getLastResponse() 检索响应。

于 2012-09-26T07:11:59.720 回答
3

与 Ducane 的回复相关:

response = yourStub._getServiceClient().getLastOperationContext().getMessageContext("In")
          .getEnvelope().toString());

失败,出现com.ctc.wstx.exc.WstxIOException异常和消息:Attempted read on closed stream

于 2014-02-06T15:44:14.720 回答
3

对于 Axis2,那些没有改变实现的奢侈/或出于 xyz 原因不想使用 JAS-WS 的人,

发现@Ducane 很有用

request = >yourStub._getServiceClient().getLastOperationContext().getMessageContext("Out")
         .getEnvelope().toString());

response = >yourStub._getServiceClient().getLastOperationContext().getMessageContext("In")
         .getEnvelope().toString());

正如@dayer 的回答所建议的那样

response = >yourStub._getServiceClient().getLastOperationContext().getMessageContext("In")
     .getEnvelope().toString());

失败并出现 com.ctc.wstx.exc.WstxIOException 异常和消息:>尝试在关闭的流上读取。

不确定“In”消息标签有什么问题,

但是在搜索时,发现以下 JIRA 票https://issues.apache.org/jira/browse/AXIS2-5469指向https://issues.apache.org/jira/browse/AXIS2-5202并在讨论中找到了一个WA 使用以下代码解决此问题,我能够收听soapRequest 的响应消息。

stub._getServiceClient().getAxisService().addMessageContextListener(
new MessageContextListener() {
    public void attachServiceContextEvent(ServiceContext sc,
        MessageContext mc) {}
    public void attachEnvelopeEvent(MessageContext mc) {
        try
        { mc.getEnvelope().cloneOMElement().serialize(System.out); }
        catch (XMLStreamException e) {}
    }
});

因为这里 MessageContextListner 是参数定义的匿名内部类,它可以访问所有封闭变量,所以我只是将一个字符串类变量定义为 latestSoapResponse 并存储响应以供进一步使用。

ByteArrayOutputStream baos = new ByteArrayOutputStream();
mc.getEnvelope().cloneOMElement().serialize(baos); 
latestSoapResponse=baos.toString();

请注意,您需要在生成肥皂请求之前添加侦听器。并且 Request MessageContext 仅在您生成soap请求后才可用。

此外,那些只想要原始soap请求响应以进行调试的人可能会看到@Sanker的回答,这里是为了使用JVM参数启用Apache commons日志记录。

于 2015-04-21T19:38:25.493 回答
2

正如 joergl 所建议的那样,我使用“SOAPHandler”将我的 ADB-stubs 更改为 JAX-WS-ones,以按照此处的描述记录请求、响应和故障:http ://www.mkyong.com/webservices/jax-ws/jax -ws-soap-handler-in-client-side/

我的处理程序看起来像这样,用于使用 log4j 记录格式良好的 XML:

public class RequestResponseHandler  implements SOAPHandler<SOAPMessageContext> {

    private static Logger log = Logger.getLogger(RequestResponseHandler.class);
    private Transformer transformer = null;
    private DocumentBuilderFactory docBuilderFactory = null;
    private DocumentBuilder docBuilder = null;

    public RequestResponseHandler() {
        try {
            transformer = TransformerFactory.newInstance().newTransformer();
            transformer.setOutputProperty(OutputKeys.INDENT, "yes");
            transformer.setOutputProperty("{http://xml.apache.org/xslt}indent-amount", "5");
            docBuilderFactory = DocumentBuilderFactory.newInstance();
            docBuilder = docBuilderFactory.newDocumentBuilder();
        } catch (TransformerConfigurationException
                | TransformerFactoryConfigurationError
                | ParserConfigurationException e) {
            log.error(e.getMessage(), e);
        }
    }

    @Override
    public void close(MessageContext arg0) {
    }

    @Override
    public boolean handleFault(SOAPMessageContext messageContext) {
        log(messageContext);
        return true;
    }

    @Override
    public boolean handleMessage(SOAPMessageContext messageContext) {
        log(messageContext);
        return true;
    }

    private void log(SOAPMessageContext messageContext) {
        String xml = "";
        SOAPMessage msg = messageContext.getMessage();
        ByteArrayOutputStream out = new ByteArrayOutputStream();
        try {
            msg.writeTo(out);
            xml = out.toString("UTF-8");
        } catch (Exception e) {
            log.error(e.getMessage(),e);
        }       

        String direction = "";
        Boolean outbound = (Boolean) messageContext.get(MessageContext.MESSAGE_OUTBOUND_PROPERTY); 
        if (outbound) { 
            direction += "Request: \n"; 
        } else { 
            direction += "Response: \n";
        } 

        log.info(direction + getXMLprettyPrinted(xml));     
    }

    @Override
    public Set<QName> getHeaders() {
        return Collections.emptySet();
    }


    public String getXMLprettyPrinted(String xml) {

        if (transformer == null || docBuilder == null)
            return xml;

        InputSource ipXML = new InputSource(new StringReader(xml));
        Document doc;

        try {
            doc = docBuilder.parse(ipXML);
            StringWriter stringWriter = new StringWriter();
            StreamResult streamResult = new StreamResult(stringWriter);
            DOMSource domSource = new DOMSource(doc);
            transformer.transform(domSource, streamResult);
            return stringWriter.toString();
        } catch (SAXException | IOException | TransformerException e) {
            log.error(e.getMessage(), e);
            return xml;
        }
    }
}

此外,我想在我的应用程序代码中重用原始 XML。所以我不得不将这些数据从 SOAPHandler 传输回我的客户端代码。如何做到这一点并不太明显。关于这个问题的更多信息可以在这篇文章中找到: 如何将附加字段与soapMessage一起发送到soap处理程序?

于 2012-09-03T00:00:45.027 回答