场景:

服务编排框架支持编排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

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

  1. ecshop后台增加|添加商店设置选项和使用方法详解

    有时候我们想在Ecshop后台做个设置.radio.checkbox 等等来控制页面的显示,看看Ecshop的设计,用到了shop_config这个商店设置功能 Ecshop后台增加|添加商店设置选项 ...

  2. txt文本框设为密码模式后,后台(服务器端)设置不了值

    txt文本框设为密码模式后,因为安全问题,后台(服务器端)设置不了值,只有在前台(客户端)复制才能显示

  3. DEV控件ASPxTextBox设置ClientEnabled="false"之后出现的问题

    DEV控件ASPxTextBox设置ClientEnabled="false"之后,js中设置文本框的值后,按钮后台点击事件中获取文本框的值为空.

  4. 为了安全请不要随意在页面中设置validateRequest="false"

    为了安全请不要随意在页面中设置validateRequest="false" 分类: ASP.NET2009-04-12 17:24 531人阅读 评论(0) 收藏 举报 asp. ...

  5. Qt在VS2013或Qt Creator 中的控制台输出方式设置

    首先值得注意的是:在写程序的时候,项目保存路径不要涉及到中文,否则容易出错! 一.Qt在VS2013中的控制台输出方式: 注意:这里是而不是Qt Application. 然后直接点击finish即可 ...

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

    通过在 Page 指令或 配置节中设置 validateRequest=false 可以禁用请求验证 说明:   请求验证过程检测到有潜在危险的客户端输入值,对请求的处理已经中止.该值可能指示危及应用 ...

  7. Webpack4 的 Tree Shaking:babel-loader设置modules: false,还是设置"sideEffects": false,待确定

    Webpack4 的 Tree Shaking:babel-loader设置modules: false,还是设置"sideEffects": false,待确定 babel-lo ...

  8. Eclipse设置之:代码注释/server 控制台输出乱码解决

    1           Eclipse设置 Configure clean up style The location is here: And the configuration should fo ...

  9. 在Form Load中设置showInTaskBar =false 或 隐藏窗口 this.Hide()时会导致注册的全局快捷键无效

    在Form Load中设置showInTaskBar =false   或 隐藏窗口 this.Hide() 会导致注册的全局快捷键无效.  反正是其中一个,有点记不清了. 在Form Shown中s ...

随机推荐

  1. 洛谷 P1372 又是毕业季I Label:None

    题目背景 “叮铃铃铃”,随着高考最后一科结考铃声的敲响,三年青春时光顿时凝固于此刻.毕业的欣喜怎敌那离别的不舍,憧憬着未来仍毋忘逝去的歌.1000多个日夜的欢笑和泪水,全凝聚在毕业晚会上,相信,这一定 ...

  2. JAVA给图片加上水印

    import java.awt.Color;       import java.awt.Font;       import java.awt.Graphics;       import java ...

  3. jq图片切换特效

    首先引入js,内容如下: (function($){$.fn.slides=function(option){option=$.extend({},$.fn.slides.option,option) ...

  4. HDU 5762

    Teacher Bo Time Limit: 4000/2000 MS (Java/Others)    Memory Limit: 131072/131072 K (Java/Others) Tot ...

  5. c#面向对象基础 静态成员、构造函数、命名空间与类库

    静态成员 属性.方法和字段等成员是对象实例所特有的,即改变一个对象实例的这些成员不影响其他的实例中的这些成员.除此之外,还有一种静态成员(也称为共享成员),例如静态方法.静态属性或静态字段.静态成员可 ...

  6. WebApp 设计要素

    从去年开始就负责公司WebApp的产品跟设计工作,最近整体大改了两个版本,也算累积了一些实际的经验.在不断学习的过程中,发现对于WebApp可以直接用于项目上的资料比较零碎,在这里总结一下,供初做 W ...

  7. C# @符号的作用, 可定义关键字为变量名

    一 字符串中的用法字符@表示,其后的字符串是个“逐字字符串”(verbatim string).@只能对字符串常量作用.1.用于文件路径以下是引用片段:string s_FilePath =" ...

  8. SRM 588 DIV1

    250 题意:有n首不同的曲子,你唱每首曲子需要花费a的时间以及一个调整的时间b,调整的时间为此首歌的曲调减去上一首歌的曲调的绝对值. 思路:我们用dp[i][k]表示前i首歌只唱k首用的最小时间花费 ...

  9. Python 第一课

    Python语言特点: 优雅,明确,简单 适合开发: Web网络和各种网络服务 系统工具和脚本 作为胶水语言把其他语言开发的模块包装起来方便使用 Python2.7.10的安装(path环境变量)   ...

  10. java之main函数(笔记)

    1.标准的main函数形式 对于main函数,只要是 public static void main(String[] args) public static void main(String... ...