• 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.interceptor.MessageSenderInterceptor$MessageSenderEndingInterceptor@17d602ac这个拦截器时。

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

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

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

    在chunk未关闭的时候:

    org.apache.cxf.jaxws.interceptors.HolderOutInterceptor@35185c1c
        org.apache.cxf.jaxws.interceptors.SwAOutInterceptor@1b83d46a
        org.apache.cxf.jaxws.interceptors.WrapperClassOutInterceptor@696eeb41
        org.apache.cxf.binding.soap.interceptor.SoapHeaderOutFilterInterceptor@3b8d3ecd
        org.apache.cxf.binding.soap.interceptor.SoapPreProtocolOutInterceptor@50f36fcb
        org.apache.cxf.interceptor.MessageSenderInterceptor@48bdd8f7
        org.apache.cxf.interceptor.LoggingOutInterceptor@de0353b
        org.apache.cxf.interceptor.AttachmentOutInterceptor@28f3964a
        org.apache.cxf.interceptor.StaxOutInterceptor@519d5d83
        org.apache.cxf.binding.soap.interceptor.SoapOutInterceptor@7d5b68d5
        org.apache.cxf.interceptor.WrappedOutInterceptor@60340199
        org.apache.cxf.interceptor.BareOutInterceptor@5e1d90a3
        org.apache.cxf.binding.soap.interceptor.SoapOutInterceptor$SoapOutEndingInterceptor@54babeeb
        org.apache.cxf.interceptor.StaxOutInterceptor$StaxOutEndingInterceptor@27a4431
        org.apache.cxf.interceptor.MessageSenderInterceptor$MessageSenderEndingInterceptor@17d602ac

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

    在chunk设置成false关闭时:

    org.apache.cxf.jaxws.interceptors.HolderOutInterceptor@7859857a
        org.apache.cxf.jaxws.interceptors.SwAOutInterceptor@1bf5df6a
        org.apache.cxf.jaxws.interceptors.WrapperClassOutInterceptor@2db493c7
        org.apache.cxf.binding.soap.interceptor.SoapHeaderOutFilterInterceptor@2c661664
        org.apache.cxf.binding.soap.interceptor.SoapPreProtocolOutInterceptor@6e1c8760
        org.apache.cxf.interceptor.MessageSenderInterceptor@37031ba1
        org.apache.cxf.interceptor.LoggingOutInterceptor@a5571f9
        org.apache.cxf.interceptor.AttachmentOutInterceptor@2b891cf8
        org.apache.cxf.interceptor.StaxOutInterceptor@312437a4
        org.apache.cxf.binding.soap.interceptor.SoapOutInterceptor@439e91fe

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

    果然很清晰的发现在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.

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

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

    demo代码在 https://github.com/xiaguangme/demo/tree/master/01.cxf_2.3.11

  • 相关阅读:
    leetCode算法题(一)
    node学习笔记1(http模块)
    mySql常用命令总结
    django学习遇到的问题解决方式
    WebSSH2 界面ssh(转载)
    垃圾回收策略学习总结
    5种数组扁平化方法
    冒泡、插入、选择、归并、快速排序
    手写ES6数组方法
    HTTP options预请求
  • 原文地址:https://www.cnblogs.com/simoncook/p/5513416.html
Copyright © 2020-2023  润新知