使用AXIS2创建的ADB-stub在客户端获取原始XML SOAP响应

我使用AXIS2创建的ADB-stub访问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? } } 

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

      soapenv:Receiver   service error    500 some fault message      

虽然这个问题已经得到了很好的回答,但我需要提前做到这一点,并且无法找到适合我的约束的合适答案,所以我为后代添加了自己的答案。

对于最近运行JDK 1.4的项目,我需要使用Axis 2版本1.4.1执行此操作,而JAX-WS存根不支持我所阅读的内容。 我最后通过使用我自己的构建器类包装SoapBuilder来捕获输入时保留ADB存根,复制输入流并将副本传递给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()检索响应。

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

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

希望这很有帮助。

与Ducane的回复有关:

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

com.ctc.wstx.exc.WstxIOExceptionexception和消息失败: 在关闭的流上尝试读取

正如joergl所建议的那样,我使用“SOAPHandler”将我的ADB-stubs更改为JAX-WS-one,以按照此处的描述记录请求,响应和错误: http ://www.mkyong.com/webservices/jax-ws/jax -ws皂处理程序function于客户端/

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

 public class RequestResponseHandler implements SOAPHandler { 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 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处理程序?

对于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.WstxIOExceptionexception并且消息:>尝试读取已关闭的流。

不确定“In”Message Lable的问题是什么,

但在搜索时,发现以下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是Argument-Defined Anonymous Inner Classes,它可以访问所有封闭变量,所以我只是将字符串类变量定义为latestSoapResponse并存储响应以供进一步使用。

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

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

那些只是想要调试目的的原始SOAP请求响应的人可以从@Sanker看到答案, 这里是为了使用JVM参数启用Apache commons日志记录。