[英]Getting raw XML SOAP-response on client side using ADB-stubs created by AXIS2
我使用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?
}
}
示例故障響應,我想獲取並記錄:
<?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>
以下是您可能正在尋找的內容, yourStub
是您通過wsdl2java生成的內容,並在您提出請求后使用以下行。 消息設置為lastOperation
並在您進行實際調用時發送:
request = yourStub._getServiceClient().getLastOperationContext().getMessageContext("Out")
.getEnvelope().toString());
response = yourStub._getServiceClient().getLastOperationContext().getMessageContext("In")
.getEnvelope().toString());
希望這很有幫助。
雖然這個問題已經得到了很好的回答,但我需要提前做到這一點,並且無法找到適合我的約束的合適答案,因此我為后代添加了自己的答案。
對於最近運行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()檢索響應。
與Ducane的回復有關:
response = yourStub._getServiceClient().getLastOperationContext().getMessageContext("In")
.getEnvelope().toString());
以com.ctc.wstx.exc.WstxIOException異常和消息失敗: 在關閉的流上嘗試讀取 。
正如joergl所建議的,我使用“SOAPHandler”將我的ADB-stubs更改為JAX-WS-one,以記錄請求,響應和故障,如下所示: http ://www.mkyong.com/webservices/jax-ws/jax -ws皂處理程序功能於客戶端/
我的處理程序看起來像這樣使用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處理程序?
對於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”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日志記錄。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.