You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.20 13:27:22