Apache CXF 3.5.2无法获取请求原始XML及响应负载问题
Apache CXF 3.5.2 获取SOAP请求/响应负载解决方案
一、修复自定义OUT拦截器获取请求负载的问题
你之前的OUT拦截器错误在于,OUT方向的消息在流阶段持有的是OutputStream而非InputStream,直接获取InputStream会返回null。正确做法是在Phase.PRE_STREAM阶段替换输出流,通过TeeOutputStream同时捕获内容并保留原输出:
public static class SoapActionOutInterceptor extends AbstractSoapInterceptor { public SoapActionOutInterceptor() { super(Phase.PRE_STREAM); } @Override public void handleMessage(SoapMessage message) throws Fault { try { // 获取原输出流 OutputStream originalOut = message.getContent(OutputStream.class); // 创建字节数组输出流用于捕获内容 ByteArrayOutputStream baos = new ByteArrayOutputStream(); // 替换为TeeOutputStream,同时写入原流和字节流 TeeOutputStream teeOut = new TeeOutputStream(originalOut, baos); message.setContent(OutputStream.class, teeOut); // 添加拦截器在SEND阶段结束后读取捕获的内容 message.getInterceptorChain().add(new AbstractSoapInterceptor(Phase.SEND_ENDING) { @Override public void handleMessage(SoapMessage msg) throws Fault { try { teeOut.flush(); byte[] payload = baos.toByteArray(); String result = new String(payload, StandardCharsets.UTF_8); System.out.println("OUT SOAP MESSAGE: " + result); } catch (IOException e) { throw new Fault(e); } } }); } catch (Exception e) { e.printStackTrace(); } } }
注册拦截器的代码保持不变,即可正确捕获发送前的SOAP请求负载。
二、无需自定义拦截器的方案
方法1:使用LoggingFeature
通过CXF自带的LoggingFeature自动启用请求/响应日志,无需编写自定义拦截器:
org.apache.cxf.endpoint.Client clientProxy = ClientProxy.getClient(atposWSPortType); LoggingFeature loggingFeature = new LoggingFeature(); loggingFeature.setPrettyLogging(true); // 格式化输出XML clientProxy.getEndpoint().getFeatures().add(loggingFeature);
启动后CXF会自动在控制台输出请求和响应的SOAP信封内容。
方法2:添加内置日志拦截器
直接使用CXF内置的日志拦截器,自动处理流复制和日志输出:
org.apache.cxf.endpoint.Client clientProxy = ClientProxy.getClient(atposWSPortType); clientProxy.getInInterceptors().add(new LoggingInInterceptor()); clientProxy.getOutInterceptors().add(new LoggingOutInterceptor()); clientProxy.getOutFaultInterceptors().add(new LoggingOutInterceptor()); clientProxy.getInFaultInterceptors().add(new LoggingInInterceptor());
方法3:手动序列化请求对象(仅获取请求内容)
如果只需要获取请求的SOAP内容,可在调用Web服务前手动将请求对象序列化为SOAP XML:
// 假设request是你的请求对象实例 JAXBContext jaxbContext = JAXBContext.newInstance(RequestClass.class); Marshaller marshaller = jaxbContext.createMarshaller(); marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true); // 序列化请求体 ByteArrayOutputStream baos = new ByteArrayOutputStream(); marshaller.marshal(request, baos); String requestBody = baos.toString(StandardCharsets.UTF_8); // 拼接SOAP信封 String soapRequest = "<soap:Envelope xmlns:soap=\"http://schemas.xmlsoap.org/soap/envelope/\">" + "<soap:Body>" + requestBody + "</soap:Body>" + "</soap:Envelope>"; System.out.println("手动生成的SOAP请求: " + soapRequest);
这种方式需要自行处理SOAP信封的命名空间等细节,适合仅需请求内容的场景。
内容的提问来源于stack exchange,提问作者Sergio
相关产品推荐
相关产品推荐

