Java CXF替换.NET SOAP服务遇传输问题,需禁用响应分块
解决CXF Web服务禁用响应分块传输的问题
我之前刚好碰到过一模一样的场景——用Java CXF替换旧的.NET SOAP服务,面对完全不能改的黑盒客户端,哪怕把响应字节和原服务做得分毫不差,客户端还是不认。折腾了好久才发现,问题出在响应分块传输上。下面给你几个亲测有效的解决办法:
方法1:直接通过CXF配置禁用分块
这是最直接的方式,通过CXF的HTTP Conduit配置关闭分块传输。
如果是代码层面配置服务端:
import org.apache.cxf.endpoint.Endpoint; import org.apache.cxf.jaxws.EndpointImpl; import org.apache.cxf.transport.http.HTTPConduit; import org.apache.cxf.transport.http.HttpClientPolicy; // 初始化你的服务实例 YourSoapServiceImpl serviceInstance = new YourSoapServiceImpl(); EndpointImpl endpoint = new EndpointImpl(yourBusInstance, serviceInstance); // 获取HTTP管道并禁用分块 HTTPConduit conduit = (HTTPConduit) endpoint.getConduit(); HttpClientPolicy clientPolicy = new HttpClientPolicy(); clientPolicy.setAllowChunking(false); conduit.setClient(clientPolicy); // 发布服务 endpoint.publish("/yourServiceEndpoint");
如果是Spring XML配置:
<jaxws:endpoint id="yourService" implementor="com.yourpackage.YourSoapServiceImpl" address="/yourServiceEndpoint"> <jaxws:properties> <entry key="org.apache.cxf.transport.http.HTTPConduit.allowChunking" value="false"/> </jaxws:properties> </jaxws:endpoint>
方法2:自定义出站拦截器强制修改响应
如果上面的配置没生效(有时候容器会覆盖CXF的设置),可以写个出站拦截器,手动移除分块相关的响应头,同时设置正确的Content-Length:
import org.apache.cxf.message.Message; import org.apache.cxf.phase.AbstractPhaseInterceptor; import org.apache.cxf.phase.Phase; import java.io.ByteArrayOutputStream; import java.util.Iterator; import javax.xml.namespace.QName; public class DisableChunkingInterceptor extends AbstractPhaseInterceptor<Message> { public DisableChunkingInterceptor() { super(Phase.PRE_STREAM); // 要在响应流写入前执行 } @Override public void handleMessage(Message message) { // 关闭分块标记 message.put(Message.CHUNKED, Boolean.FALSE); // 计算响应内容长度并设置Content-Length头 ByteArrayOutputStream outputStream = (ByteArrayOutputStream) message.getContent(ByteArrayOutputStream.class); if (outputStream != null) { long contentLength = outputStream.size(); message.put(Message.CONTENT_LENGTH, contentLength); } // 移除Transfer-Encoding头(防止容器自动添加) Iterator<?> headerIterator = message.getHeaders().iterator(); while (headerIterator.hasNext()) { Object header = headerIterator.next(); if (header instanceof org.apache.cxf.headers.Header) { QName headerName = ((org.apache.cxf.headers.Header) header).getName(); if ("Transfer-Encoding".equalsIgnoreCase(headerName.getLocalPart())) { headerIterator.remove(); } } } } }
然后把这个拦截器注册到服务端:
endpoint.getOutInterceptors().add(new DisableChunkingInterceptor());
方法3:检查容器的分块设置
如果是用Tomcat、Jetty这类容器部署,还要确认容器本身有没有强制开启分块。比如Tomcat的server.xml里的Connector配置,有些参数(比如compression、connectionTimeout)可能会触发自动分块,必要时调整容器的HTTP配置,确保响应不会被容器二次处理。
我当时是用第一种方法就解决了问题,不过如果你的环境比较特殊,拦截器的方式绝对能搞定——毕竟黑盒客户端的兼容性问题,有时候就得靠这种“硬修正”的办法。
内容的提问来源于stack exchange,提问作者MrMcCools
相关产品推荐
相关产品推荐

