cxf client在后台不通且chunk设置为false的时候不能在控制台输出请求日志

场景:

服务编排框架支持编排webservice服务。call webservice的client是基于cxf做的。为了使用服务编排的开发者调试与定位问题方便,需要将webservice的请求与响应报文打出来。

这个诉求不是很复杂加上LoggingInInterceptor(打印响应报文)与LoggingOutInterceptor(打印请求报文)两个拦截器即可。

好,开始考虑异常场景,当提供webservice的服务后台不通时,理论上也是应该可以打出请求报文的,但是在对cxf的client的httpClientPolicy的chunk设置成false之后,请求的报文就不会被打出了。

分析:

分析源码后发现cxf依赖大量的拦截器,可以说对拦截器这个pattern用的还是比较深入的:

1. 拦截的phase有很多

2.触发拦截后还可以注册回调

3.拦截器形成自己的chain

4.触发拦截器执行过程中还可以动态增加拦截器

触发拦截器调用逻辑的代码在

org.apache.cxf.phase.PhaseInterceptorChain.doIntercept(Message)

的255行: currentInterceptor.handleMessage(message);

通过调用堆栈不难发现,触发输出日志动作是在执行org.apache.cxf.inte[email protected]17d602ac这个拦截器时。

可以猜测在chunk设置成false是没有成功执行到这个拦截器的。

好,对比两种场景下执行的拦截器的情况

----------------------------------------------

在chunk未关闭的时候:

[email protected]
    [email protected]
    [email protected]eeb41
    org.apa[email protected]3b8d3ecd
    org.ap[email protected]50f36fcb
    [email protected]
    [email protected]
    [email protected]
    [email protected]
    [email protected]8d5
    [email protected]
    [email protected]
    org.apache.cxf.bindi[email protected]54babeeb
    org.apa[email protected]27a4431
    org.apache.cxf.inte[email protected]17d602ac

===========================

在chunk设置成false关闭时:

[email protected]
    [email protected]
    [email protected]493c7
    org.apa[email protected]2c661664
    org.ap[email protected]6e1c8760
    [email protected]
    [email protected]
    [email protected]
    [email protected]
    [email protected]1fe

----------------------------------------------

果然很清晰的发现在org.apache.cxf.binding.soap.interceptor.SoapOutInterceptor执行时出现了异常,使得拦截器执行不下去了,日志如下,显而易见,服务不通:

exception, unwinding now
org.apache.cxf.binding.soap.SoapFault: Error writing to XMLStreamWriter.
    at org.apache.cxf.binding.soap.interceptor.SoapOutInterceptor.writeSoapEnvelopeStart(SoapOutInterceptor.java:175)
    at org.apache.cxf.binding.soap.interceptor.SoapOutInterceptor.handleMessage(SoapOutInterceptor.java:81)
    at org.apache.cxf.binding.soap.interceptor.SoapOutInterceptor.handleMessage(SoapOutInterceptor.java:61)
    at org.apache.cxf.phase.PhaseInterceptorChain.doIntercept(PhaseInterceptorChain.java:255)
    at org.apache.cxf.endpoint.ClientImpl.invoke(ClientImpl.java:544)
    at org.apache.cxf.endpoint.ClientImpl.invoke(ClientImpl.java:341)
    at org.apache.cxf.endpoint.ClientImpl.invoke(ClientImpl.java:294)
    at org.apache.cxf.frontend.ClientProxy.invokeSync(ClientProxy.java:73)
    at org.apache.cxf.jaxws.JaxWsClientProxy.invoke(JaxWsClientProxy.java:124)
    at com.sun.proxy.$Proxy26.queryUser(Unknown Source)
    at org.simonme.demo.cxf.client.user.UserService_UserServicePort_Client.main(UserService_UserServicePort_Client.java:77)
Caused by: javax.xml.stream.XMLStreamException: java.net.ConnectException: Connection refused: connect
    at com.sun.xml.internal.stream.writers.XMLStreamWriterImpl.writeStartElement(XMLStreamWriterImpl.java:1344)
    at org.apache.cxf.binding.soap.interceptor.SoapOutInterceptor.writeSoapEnvelopeStart(SoapOutInterceptor.java:122)
    ... 10 more
Caused by: java.net.ConnectException: Connection refused: connect
    at java.net.DualStackPlainSocketImpl.waitForConnect(Native Method)
    at java.net.DualStackPlainSocketImpl.socketConnect(DualStackPlainSocketImpl.java:85)
    at java.net.AbstractPlainSocketImpl.doConnect(AbstractPlainSocketImpl.java:339)
    at java.net.AbstractPlainSocketImpl.connectToAddress(AbstractPlainSocketImpl.java:200)
    at java.net.AbstractPlainSocketImpl.connect(AbstractPlainSocketImpl.java:182)
    at java.net.PlainSocketImpl.connect(PlainSocketImpl.java:172)
    at java.net.SocksSocketImpl.connect(SocksSocketImpl.java:392)
    at java.net.Socket.connect(Socket.java:579)

org.apache.cxf.io.AbstractThresholdOutputStream.write(int)

@Override
    public void write(int b) throws IOException {
        if (buffer != null) {
            buffer.write(b);
            if (buffer.size() >= threshold) {
                thresholdReached();
                unBuffer();
            }
            return;
        }
        super.write(b);
    }

threshold 在chunk设置成false时 为0 ,不设置时(默认true) 为4096

当设置成0时,一定会触发unBuffer逻辑,这个逻辑会去请求后台,此时后台又不通 那么就出现了异常。具体可以看上面日志的异常栈。
   
    如何设置的4096
    看org.apache.cxf.transports.http.configuration.HTTPClientPolicy.getChunkingThreshold()
   
threshold 如何设置的0

if (csPolicy.isAllowChunking()
            && isChunkingSupported(message, connection.getRequestMethod())) {
            //TODO: The chunking mode be configured or at least some
            // documented client constant.
            //use -1 and allow the URL connection to pick a default value
            isChunking = true;
            chunkThreshold = csPolicy.getChunkingThreshold();
            if (chunkThreshold <= 0) {
                chunkThreshold = 0;
                connection.setChunkedStreamingMode(-1);
            }
        }

org.apache.cxf.transport.http.HTTPConduit.prepare(Message)
        方法中chunkThreshold初始值为0  因为isAllowChunking为false 所以上面逻辑不会进入,所以chunkThreshold依然为0
       
        为什么设置启用chunk,就要设置成4096?
        you’ll be receiving in some arbitrary chunk size, (4096 or 8192 is frequently a good match for network buffer sizes)
       
        还有些类库 默认是2048的
        The default chunk size in Apache HttpClient 4.3 is set to 2048 bytes.

如何解决这个问题,可以考虑修改(重写)这个拦截器的触发时机等。

时间: 2024-10-13 09:28:07

cxf client在后台不通且chunk设置为false的时候不能在控制台输出请求日志的相关文章

(转)通过在 Page 指令或 配置节中设置 validateRequest=false 可以禁用请求验证

通过在 Page 指令或 配置节中设置 validateRequest=false 可以禁用请求验证 说明:   请求验证过程检测到有潜在危险的客户端输入值,对请求的处理已经中止.该值可能指示危及应用程序安全的尝试,如跨站点的脚本攻击.通过在   Page   指令或   配置节中设置   validateRequest=false   可以禁用请求验证.但是,在这种情况下,强烈建议应用程序显式检查所有输入. 解决方法: 方法1. 在.aspx页面中添加: <%@   Page   valida

设置 sqlserver Profiler 只监控 EF的sql执行请求

当我们用EF执行语句的时候,可以使用 sqlserver Profiler来监控到底执行了哪些sql语句,但是默认他是监控全局的,我们只想监控Ef的语句,这里如下设置 这样就只会监控 EF产生的 sql语句了 设置 sqlserver Profiler 只监控 EF的sql执行请求

thinkphp将APP_DEBUG常量设置为false后报错的问题

ThinkPHP 将 APP_DEBUG 常量设置为 false 后出现了下面的问题: Parse error: syntax error, unexpected T_STRING in \www\Runtime\~app.php on line 1 或者直接报"服务器错误", 怎么办? 这个和 PHP 有关系,在 php.ini 里修改配置 short_open_tag = On 因为 app.class.php 里面的 build 方法: 当开启了调试模式后,会获取相关文件的内容

SpriteKit在复制节点时留了一个巨坑给开发者,需要开发者手动把复制节点的isPaused设置为false

根据When an overlay node with actions is copied there is currently a SpriteKit bug where the node’s isPaused property might be set to true提示,SpriteKit有一个Bug需要开发者自己来填. SpriteNode节点在被copy()复制后,会自动被设置为暂停,也就是节点的所有Action全部不可用,如果需要使用node.run(SKAction.run{//c

django开发环境setting.py里面设置debug=false时却成功加载静态文件?

django开发环境setting.py里面设置debug=false时却成功加载静态文件?按理来说应该是加载失败的. 启动服务器,运行正常,但是静态文件如css,js,图片是无法加载的. 问题: 解答:问题在于使用的是谷歌浏览器,默认使用了缓存.导致每次访问同一个url时,都返回的是缓存里面的东西. 通过谷歌浏览器里面的开发者工具network下面的选项能禁用缓存.禁用缓存之后,则在django开发环境里面,运行 python manage.py runserver,如将DEBUG的值设为Tr

org.apache.http.client.HttpClient; HttpClient 4.3超时设置

可用的code public static String doPost(String url, String params, String contentType) /*throws IOException */{ CloseableHttpClient client = HttpClients.createDefault(); RequestConfig requestConfig = RequestConfig.custom().setSocketTimeout(httpSoTimeout)

Wordpress后台自动更新相关设置与解答

由于Wordpress后台有很多内容是自动的,除了上文中提到的"版本更新通知"."插件更新通知"和"主题更新通知"以外,还有核心文件更新通知和翻译文件更新(自动),其实在上文的版本更新中心里面有提及相关的关闭通知方式.关闭了通知以后,wordpress博客系统有默认开启更新某些功能和默认关闭某些功能,那么无忧小编今天给大家介绍下如何设置后台自动更新. 遇到新建的Wordpress站点时,有些自动更新是默认关闭的,比如Wordpress程序的版本.

ActiveMQ管理后台以及消费者密码设置

1.管理后台密码 (1)ActiveMQ使用的是jetty服务器打开apache-activemq-5.8.0\conf\jetty.xml 找到 <pre name="code" class="html"> <bean id="securityConstraint" class="org.eclipse.jetty.util.security.Constraint"> <property nam

asp.net通过后台代码给前台设置css样式,下拉列表在js中的取值

后台根据不同的用户登陆隐藏或显示前台div标签 前台: 将div声明成服务器端控件 <div id="div1" runat="server">....</div> 后台 隐藏: this.div1.Style.Add("display", "none"); 显示: this.div1.Style.Add("display", "block"); 必须要加 run