在 JaxWSClient 上启用 LoggingInInterceptor 时出现“流已关闭”错误

Posted

技术标签:

【中文标题】在 JaxWSClient 上启用 LoggingInInterceptor 时出现“流已关闭”错误【英文标题】:"stream is closed" error when enabling LoggingInInterceptor on JaxWSClient 【发布时间】:2013-10-09 09:38:52 【问题描述】:

我遇到了一个奇怪的问题,似乎无法解决问题。基本上需要记录被发送到网络服务和接收(消费者)的soap XML。我相信正确的方法是使用 Apache 提供的开箱即用的拦截器。这些工作正常,但是我们有一个特殊情况,其中一个方法接受大量参数/对象并返回大量参数/对象,这显然会创建一个大型肥皂请求/响应 xml。肥皂请求/响应始终正确打印,但抛出以下错误:

应用配置

弹簧配置:

<jaxws:client id="serviceClient"
              serviceClass="com.services.stubs.ServiceAPI"
              address="$service.url">
    <jaxws:inInterceptors>
        <ref bean="incomingInterceptor"/>
    </jaxws:inInterceptors>
    <jaxws:outInterceptors>
        <ref bean="outgoingInterceptor"/>
    </jaxws:outInterceptors>
</jaxws:client>

我的拦截器类:

public class OutLoggingInterceptor extends LoggingOutInterceptor

    public OutLoggingInterceptor()
    
        super(Phase.PRE_STREAM);
    



public class InLoggingInterceptor extends LoggingInInterceptor

    public InLoggingInterceptor()
    
        super(Phase.RECEIVE);
    

抛出错误:

org.apache.cxf.interceptor.Fault: stream is closed
    at org.apache.cxf.interceptor.LoggingInInterceptor.logging(LoggingInInterceptor.java:167) ~[cxf-api-2.7.6.jar:2.7.6]
    at org.apache.cxf.interceptor.LoggingInInterceptor.handleMessage(LoggingInInterceptor.java:78) ~[cxf-api-2.7.6.jar:2.7.6]
    at org.apache.cxf.phase.PhaseInterceptorChain.doIntercept(PhaseInterceptorChain.java:271) [cxf-api-2.7.6.jar:2.7.6]
    at org.apache.cxf.endpoint.ClientImpl.onMessage(ClientImpl.java:811) [cxf-api-2.7.6.jar:2.7.6]
    at org.apache.cxf.transport.http.HTTPConduit$WrappedOutputStream.handleResponseInternal(HTTPConduit.java:1590) [cxf-rt-transports-http-2.7.6.jar:2.7.6]
    at org.apache.cxf.transport.http.HTTPConduit$WrappedOutputStream.handleResponse(HTTPConduit.java:1486) [cxf-rt-transports-http-2.7.6.jar:2.7.6]
    at org.apache.cxf.transport.http.HTTPConduit$WrappedOutputStream.close(HTTPConduit.java:1305) [cxf-rt-transports-http-2.7.6.jar:2.7.6]
    at org.apache.cxf.io.CacheAndWriteOutputStream.postClose(CacheAndWriteOutputStream.java:50) [cxf-api-2.7.6.jar:2.7.6]
    at org.apache.cxf.io.CachedOutputStream.close(CachedOutputStream.java:223) [cxf-api-2.7.6.jar:2.7.6]
    at org.apache.cxf.transport.AbstractConduit.close(AbstractConduit.java:56) [cxf-api-2.7.6.jar:2.7.6]
    at org.apache.cxf.transport.http.HTTPConduit.close(HTTPConduit.java:623) [cxf-rt-transports-http-2.7.6.jar:2.7.6]
    at org.apache.cxf.interceptor.MessageSenderInterceptor$MessageSenderEndingInterceptor.handleMessage(MessageSenderInterceptor.java:62) [cxf-api-2.7.6.jar:2.7.6]
    at org.apache.cxf.phase.PhaseInterceptorChain.doIntercept(PhaseInterceptorChain.java:271) [cxf-api-2.7.6.jar:2.7.6]
    at org.apache.cxf.endpoint.ClientImpl.doInvoke(ClientImpl.java:541) [cxf-api-2.7.6.jar:2.7.6]
    at org.apache.cxf.endpoint.ClientImpl.invoke(ClientImpl.java:474) [cxf-api-2.7.6.jar:2.7.6]
    at org.apache.cxf.endpoint.ClientImpl.invoke(ClientImpl.java:377) [cxf-api-2.7.6.jar:2.7.6]
    at org.apache.cxf.endpoint.ClientImpl.invoke(ClientImpl.java:330) [cxf-api-2.7.6.jar:2.7.6]
    at org.apache.cxf.frontend.ClientProxy.invokeSync(ClientProxy.java:96) [cxf-rt-frontend-simple-2.7.6.jar:2.7.6]
    at org.apache.cxf.jaxws.JaxWsClientProxy.invoke(JaxWsClientProxy.java:134) [cxf-rt-frontend-jaxws-2.7.6.jar:2.7.6]

【问题讨论】:

你尝试过 AbstractSoapInterceptor 吗? 【参考方案1】:

我可以提出几种解决方案。如果其中任何一个对您有用,请告知。

1) 你为什么要从 LoggingOutInterceptor 继承?如果您只需要指定添加它的阶段,只需在 Spring 上下文配置中使用适当的构造函数。

2) 我在使用 Apache CXF 实现 SOAP 服务时遇到了类似的错误。 A 在拦截器链中有 2 个自定义拦截器。其中之一是读取消息的输入流以解析它以执行一些自定义操作。问题是 Xerces 在解析后关闭了输入流,因此其他拦截器正在获取已经关闭的输入流。

对我有用的唯一解决方案是使用 this 解决方案复制输入流。

类似:

// Exception handling ommitted

InputStream originalStream = soapMessage.getContent(InputStream.class);

// Reading contents of original stream into memory
ByteArrayOutputStream baos = new ByteArrayOutputStream();
byte[] buffer = new byte[1024];
int len;
while ((len = originalStream.read(buffer)) > -1) 
    baos.write(buffer, 0, len);

baos.flush();
baos.close();

// Open new InputStreams using the recorded bytes
InputStream streamForThisInterceptor = new ByteArrayInputStream(baos.toByteArray());
InputStream streamForOtherInterceptors = new ByteArrayInputStream(baos.toByteArray());

// Replacing stream for other interceptors
soapMessage.setContent(InputStream.class, streamForOtherInterceptors);

糟糕的解决方案,但它是唯一有效的解决方案。

3) 你也可以尝试使用来自 Apache commons-io 的 CloseShieldInputStream,也许你会有更好的运气。

【讨论】:

以上是关于在 JaxWSClient 上启用 LoggingInInterceptor 时出现“流已关闭”错误的主要内容,如果未能解决你的问题,请参考以下文章

Logging系统

如果 DEBUG 为 True,也启用 Django 日志记录

在具有 Java 8 的嵌入式 Tomcat 8.5 上启用 TLS 握手的可观察性(日志记录/指标)

ProxySQL Query Logging

LTE Manual ——Logging(翻译)

启用详细的日志: