是否可以使用 apache cxf 发送打印精美的 SOAP 请求?
Is it possible to send a pretty printed SOAP request with apache cxf?
我正在使用 apache cxf 库作为我们的 SOAP 客户端来将 SOAP 请求传输到特定端点。
不幸的是,如果数据排成一行(这几乎是标准),这个端点似乎确实很难正确解析数据。我已经编写了一个简单的测试客户端,它将 RAW 字符串发送到该端点,并且我能够发现如果 SOAP 消息打印得很好,可以处理请求。如果我在一行中发送完全相同的请求,服务器会响应 HTTP/1.1 500 Internal Server Error.
我已经提交了错误报告,但我担心接收公司会要求我发送打印好的数据。
apache cxf 可以吗?
我发现 another question 帮助我找到了满足我需求的解决方案。
从那开始 post 我能够采用以下代码来满足我的需要
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.io.StringReader;
import java.io.StringWriter;
import javax.xml.transform.OutputKeys;
import javax.xml.transform.Source;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerException;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.stream.StreamResult;
import javax.xml.transform.stream.StreamSource;
import org.apache.cxf.binding.soap.interceptor.SoapPreProtocolOutInterceptor;
import org.apache.cxf.helpers.IOUtils;
import org.apache.cxf.interceptor.Fault;
import org.apache.cxf.io.CachedOutputStream;
import org.apache.cxf.message.Message;
import org.apache.cxf.phase.AbstractPhaseInterceptor;
import org.apache.cxf.phase.Phase;
public class PrettyPrintingOutInterceptor extends AbstractPhaseInterceptor<Message> {
public PrettyPrintingOutInterceptor(int indent) {
super(Phase.PRE_STREAM);
addBefore(SoapPreProtocolOutInterceptor.class.getName());
}
@Override
public void handleMessage(Message message) throws Fault {
boolean isOutbound = false;
isOutbound = message == message.getExchange().getOutMessage()
|| message == message.getExchange().getOutFaultMessage();
if (isOutbound) {
OutputStream os = message.getContent(OutputStream.class);
CachedStream cs = new CachedStream();
message.setContent(OutputStream.class, cs);
message.getInterceptorChain().doIntercept(message);
try {
cs.flush();
CachedOutputStream csnew = (CachedOutputStream) message
.getContent(OutputStream.class);
// get current payload
String soapMessage = IOUtils.toString(csnew.getInputStream());
// manipulate payload
soapMessage = prettyPrint(soapMessage, 3);
// Write new data into the OutputStream from above
ByteArrayInputStream bin = new ByteArrayInputStream(soapMessage.getBytes());
CachedOutputStream.copyStream(bin, os, 1024);
os.flush();
} catch (IOException | TransformerException e) {
// error handling
} finally {
// Important! Close streams!
try {
cs.close();
} catch (IOException e) {
}
try {
os.close();
} catch (IOException e) {
}
}
}
}
private String prettyPrint(String xml, int indent) throws TransformerException {
Source xmlInput = new StreamSource(new StringReader(xml));
StringWriter stringWriter = new StringWriter();
StreamResult xmlOutput = new StreamResult(stringWriter);
TransformerFactory transformerFactory = TransformerFactory.newInstance();
Transformer transformer = transformerFactory.newTransformer();
transformer.setOutputProperty(OutputKeys.INDENT, "yes");
transformer.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "yes");
transformer.setOutputProperty("{http://xml.apache.org/xslt}indent-amount", "" + indent);
transformer.transform(xmlInput, xmlOutput);
return xmlOutput.getWriter().toString();
}
private class CachedStream extends CachedOutputStream {
public CachedStream() {
super();
}
protected void doFlush() throws IOException {
currentStream.flush();
}
protected void doClose() throws IOException {
}
protected void onWrite() throws IOException {
}
}
}
并使用 client.getOutInterceptors().add(new PrettyPrintingOutInterceptor());
将此 class 中的对象添加到客户端
我正在使用 apache cxf 库作为我们的 SOAP 客户端来将 SOAP 请求传输到特定端点。 不幸的是,如果数据排成一行(这几乎是标准),这个端点似乎确实很难正确解析数据。我已经编写了一个简单的测试客户端,它将 RAW 字符串发送到该端点,并且我能够发现如果 SOAP 消息打印得很好,可以处理请求。如果我在一行中发送完全相同的请求,服务器会响应 HTTP/1.1 500 Internal Server Error.
我已经提交了错误报告,但我担心接收公司会要求我发送打印好的数据。
apache cxf 可以吗?
我发现 another question 帮助我找到了满足我需求的解决方案。
从那开始 post 我能够采用以下代码来满足我的需要
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.io.StringReader;
import java.io.StringWriter;
import javax.xml.transform.OutputKeys;
import javax.xml.transform.Source;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerException;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.stream.StreamResult;
import javax.xml.transform.stream.StreamSource;
import org.apache.cxf.binding.soap.interceptor.SoapPreProtocolOutInterceptor;
import org.apache.cxf.helpers.IOUtils;
import org.apache.cxf.interceptor.Fault;
import org.apache.cxf.io.CachedOutputStream;
import org.apache.cxf.message.Message;
import org.apache.cxf.phase.AbstractPhaseInterceptor;
import org.apache.cxf.phase.Phase;
public class PrettyPrintingOutInterceptor extends AbstractPhaseInterceptor<Message> {
public PrettyPrintingOutInterceptor(int indent) {
super(Phase.PRE_STREAM);
addBefore(SoapPreProtocolOutInterceptor.class.getName());
}
@Override
public void handleMessage(Message message) throws Fault {
boolean isOutbound = false;
isOutbound = message == message.getExchange().getOutMessage()
|| message == message.getExchange().getOutFaultMessage();
if (isOutbound) {
OutputStream os = message.getContent(OutputStream.class);
CachedStream cs = new CachedStream();
message.setContent(OutputStream.class, cs);
message.getInterceptorChain().doIntercept(message);
try {
cs.flush();
CachedOutputStream csnew = (CachedOutputStream) message
.getContent(OutputStream.class);
// get current payload
String soapMessage = IOUtils.toString(csnew.getInputStream());
// manipulate payload
soapMessage = prettyPrint(soapMessage, 3);
// Write new data into the OutputStream from above
ByteArrayInputStream bin = new ByteArrayInputStream(soapMessage.getBytes());
CachedOutputStream.copyStream(bin, os, 1024);
os.flush();
} catch (IOException | TransformerException e) {
// error handling
} finally {
// Important! Close streams!
try {
cs.close();
} catch (IOException e) {
}
try {
os.close();
} catch (IOException e) {
}
}
}
}
private String prettyPrint(String xml, int indent) throws TransformerException {
Source xmlInput = new StreamSource(new StringReader(xml));
StringWriter stringWriter = new StringWriter();
StreamResult xmlOutput = new StreamResult(stringWriter);
TransformerFactory transformerFactory = TransformerFactory.newInstance();
Transformer transformer = transformerFactory.newTransformer();
transformer.setOutputProperty(OutputKeys.INDENT, "yes");
transformer.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "yes");
transformer.setOutputProperty("{http://xml.apache.org/xslt}indent-amount", "" + indent);
transformer.transform(xmlInput, xmlOutput);
return xmlOutput.getWriter().toString();
}
private class CachedStream extends CachedOutputStream {
public CachedStream() {
super();
}
protected void doFlush() throws IOException {
currentStream.flush();
}
protected void doClose() throws IOException {
}
protected void onWrite() throws IOException {
}
}
}
并使用 client.getOutInterceptors().add(new PrettyPrintingOutInterceptor());