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

如何在触发WebServiceException前拦截含无效字符的SOAP响应XML?

解决方案:在XML解析前过滤无效字符

你的问题核心在于:JAX-WS客户端的XML解析器(此处为Woodstox)会在读取响应流的第一时间校验字符合法性,而各类拦截器/处理器都是在解析完成后才介入,所以异常会提前触发。要解决这个问题,必须在流被解析之前就过滤掉无效字符,用FilterInputStream是完全可行的方案,以下是具体实现步骤(以Apache CXF为例,SpringBoot集成WebService常用CXF):

1. 实现自定义输入流过滤器

创建一个继承FilterInputStream的类,在读取字节时过滤掉0x1a(或其他XML无效字符):

import java.io.FilterInputStream;
import java.io.IOException;
import java.io.InputStream;

public class InvalidCharFilterStream extends FilterInputStream {

    protected InvalidCharFilterStream(InputStream in) {
        super(in);
    }

    @Override
    public int read() throws IOException {
        int ch;
        // 循环读取,跳过0x1a字符
        do {
            ch = super.read();
        } while (ch == 0x1A);
        return ch;
    }

    @Override
    public int read(byte[] b, int off, int len) throws IOException {
        int bytesRead = super.read(b, off, len);
        if (bytesRead == -1) {
            return -1;
        }

        int validPos = off;
        // 遍历字节数组,移除0x1a字符
        for (int i = off; i < off + bytesRead; i++) {
            if (b[i] != 0x1A) {
                b[validPos++] = b[i];
            }
        }
        // 返回有效字节数
        return validPos - off;
    }
}

2. 自定义HTTP传输管道

替换CXF默认的HTTPConduit,让它返回我们的过滤流:

import org.apache.cxf.transport.http.HTTPConduit;
import org.apache.cxf.transport.http.HTTPURLConnection;
import org.apache.cxf.Bus;
import org.apache.cxf.endpoint.EndpointInfo;
import org.apache.cxf.transport.ConduitInitiator;

import java.io.IOException;
import java.io.InputStream;

public class CustomHTTPConduit extends HTTPConduit {

    public CustomHTTPConduit(ConduitInitiator initiator, Bus bus, EndpointInfo targetInfo) {
        super(initiator, bus, targetInfo);
    }

    @Override
    protected InputStream getInputStream(HTTPURLConnection connection) throws IOException {
        // 获取原始输入流,包装成过滤流返回
        InputStream originalStream = super.getInputStream(connection);
        return new InvalidCharFilterStream(originalStream);
    }
}

3. 配置WebService客户端使用自定义管道

在创建客户端代理时,替换默认的传输管道:

import org.apache.cxf.endpoint.Client;
import org.apache.cxf.frontend.ClientProxy;
import org.apache.cxf.jaxws.JaxWsProxyFactoryBean;

import java.net.URL;

public class PolizaClient {

    public static void main(String[] args) throws Exception {
        JaxWsProxyFactoryBean factory = new JaxWsProxyFactoryBean();
        factory.setServiceClass(PolizaSoap.class);
        factory.setAddress("http://example.org.co/your-webservice-endpoint");
        
        // 创建客户端代理
        PolizaSoap polizaSoap = (PolizaSoap) factory.create();
        
        // 获取CXF客户端实例,替换管道
        Client client = ClientProxy.getClient(polizaSoap);
        HTTPConduit originalConduit = (HTTPConduit) client.getConduit();
        CustomHTTPConduit customConduit = new CustomHTTPConduit(
                originalConduit.getConduitInitiator(),
                client.getBus(),
                client.getEndpoint().getEndpointInfo()
        );
        client.setConduit(customConduit);
        
        // 现在调用方法就不会触发无效字符异常了
        ArrayOfPolizas result = polizaSoap.Polizas("param1", "param2", "param3");
    }
}

关键说明

  • 为什么之前的拦截器无效?因为SOAPHandler、ClientInterceptor等组件都是在XML解析完成、SOAP消息已经被封装成Java对象后才执行,而Woodstox解析器在读取流的阶段就会校验字符,异常触发在这些拦截逻辑之前。
  • 如果使用的是Metro(Oracle的JAX-WS实现),核心思路依然是替换输入流,但需要通过自定义TransportPipe来实现,步骤类似。

内容的提问来源于stack exchange,提问作者Olivetz

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.31 09:31:01