我们正在使用Apache CXF 3.1.6
的最新版本,我在代码中发现了一个有趣的情况。
假设我们有一个名为InterceptorA
的拦截器,在我们的例子中我们希望它触发正常输出和错误输出,所以我们在两者中都注册了它:
当InterceptorA
调用服务时会开始有趣,这会引发RuntimeException
。
如果在常规拦截器链中发生这种情况,InterceptorA
将被调用两次!因为抛出RuntimeException
时。我们输入 out fault 链,再次呼叫InterceptorA
,然后再次呼叫该服务......
我们不可避免地会在 out fault 链中获得RuntimeException
。现在,由于我不理解的原因,CXF返回一个带有HTTP 200的空消息。
因此...
对于双重调用问题,我在考虑Message
中的一个简单标志,说明之前是否调用了InterceptorA
。如果没有,我们可以做常规。但问题仍然存在,当我们处于 out fault 链并且RuntimeException
发生时。
为什么结果200 OK?为什么身体是空的?
为了完成问题,我提供了这种情况的日志。我加快了这个过程。首先,我们可以看到Fault: Service error
这是我在服务中强制使用的RuntimeException
。我们进入 out故障链,然后我抛出RuntimeException: Interceptor error
。
接下来我要观察的是SoapUI中的空响应。
16-06-22 19:12:36 [W] [LogUtils.java:449] Application {http://domain.com/service/}EEMediationServiceImplService#{http://domain.com/service/}transfer has thrown exception, unwinding now
org.apache.cxf.interceptor.Fault: Service error
at org.apache.cxf.service.invoker.AbstractInvoker.createFault(AbstractInvoker.java:162) ~[cxf-core-3.1.6.jar:3.1.6]
at org.apache.cxf.jaxws.AbstractJAXWSMethodInvoker.createFault(AbstractJAXWSMethodInvoker.java:267) ~[cxf-rt-frontend-jaxws-3.1.6.jar:3.1.6]
at org.apache.cxf.service.invoker.AbstractInvoker.invoke(AbstractInvoker.java:128) ~[cxf-core-3.1.6.jar:3.1.6]
at org.apache.cxf.jaxws.AbstractJAXWSMethodInvoker.invoke(AbstractJAXWSMethodInvoker.java:232) ~[cxf-rt-frontend-jaxws-3.1.6.jar:3.1.6]
at org.apache.cxf.jaxws.JAXWSMethodInvoker.invoke(JAXWSMethodInvoker.java:85) ~[cxf-rt-frontend-jaxws-3.1.6.jar:3.1.6]
at org.apache.cxf.service.invoker.AbstractInvoker.invoke(AbstractInvoker.java:74) ~[cxf-core-3.1.6.jar:3.1.6]
at org.apache.cxf.interceptor.ServiceInvokerInterceptor$1.run(ServiceInvokerInterceptor.java:59) ~[cxf-core-3.1.6.jar:3.1.6]
at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:511) ~[na:1.8.0_91]
at java.util.concurrent.FutureTask.run(FutureTask.java:266) ~[na:1.8.0_91]
at org.apache.cxf.interceptor.ServiceInvokerInterceptor$2.run(ServiceInvokerInterceptor.java:126) ~[cxf-core-3.1.6.jar:3.1.6]
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142) ~[na:1.8.0_91]
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617) ~[na:1.8.0_91]
at java.lang.Thread.run(Thread.java:745) [na:1.8.0_91]
Caused by: java.lang.RuntimeException: Service error
at pl.ds.eemediation.service.INServiceStub.transfer(INServiceStub.java:64) ~[classes/:na]
at pl.ds.eemediation.service.EEMediationServiceImpl.transfer(EEMediationServiceImpl.java:102) ~[classes/:na]
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:1.8.0_91]
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ~[na:1.8.0_91]
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:1.8.0_91]
at java.lang.reflect.Method.invoke(Method.java:498) ~[na:1.8.0_91]
at org.apache.cxf.service.invoker.AbstractInvoker.performInvocation(AbstractInvoker.java:180) ~[cxf-core-3.1.6.jar:3.1.6]
at org.apache.cxf.jaxws.JAXWSMethodInvoker.performInvocation(JAXWSMethodInvoker.java:66) ~[cxf-rt-frontend-jaxws-3.1.6.jar:3.1.6]
at org.apache.cxf.service.invoker.AbstractInvoker.invoke(AbstractInvoker.java:96) ~[cxf-core-3.1.6.jar:3.1.6]
... 10 common frames omitted
16-06-22 19:12:36 [W] [LogUtils.java:449] Application {http://domain.com/service/}EEMediationServiceImplService#{http://domain.com/service/}transfer has thrown exception, unwinding now
java.lang.RuntimeException: Interceptor error
at pl.ds.eemediation.antifraud.interceptors.AntifraudInterceptor.handleMessage(AntifraudInterceptor.java:45) ~[classes/:na]
at org.apache.cxf.phase.PhaseInterceptorChain.doIntercept(PhaseInterceptorChain.java:308) [cxf-core-3.1.6.jar:3.1.6]
at org.apache.cxf.interceptor.AbstractFaultChainInitiatorObserver.onMessage(AbstractFaultChainInitiatorObserver.java:112) [cxf-core-3.1.6.jar:3.1.6]
at org.apache.cxf.phase.PhaseInterceptorChain.wrapExceptionAsFault(PhaseInterceptorChain.java:366) [cxf-core-3.1.6.jar:3.1.6]
at org.apache.cxf.phase.PhaseInterceptorChain.doIntercept(PhaseInterceptorChain.java:324) [cxf-core-3.1.6.jar:3.1.6]
at org.apache.cxf.transport.ChainInitiationObserver.onMessage(ChainInitiationObserver.java:121) [cxf-core-3.1.6.jar:3.1.6]
at org.apache.cxf.transport.http.AbstractHTTPDestination.invoke(AbstractHTTPDestination.java:254) [cxf-rt-transports-http-3.1.6.jar:3.1.6]
at org.apache.cxf.transport.http_jetty.JettyHTTPDestination.doService(JettyHTTPDestination.java:234) [cxf-rt-transports-http-jetty-3.1.6.jar:3.1.6]
at org.apache.cxf.transport.http_jetty.JettyHTTPHandler.handle(JettyHTTPHandler.java:70) [cxf-rt-transports-http-jetty-3.1.6.jar:3.1.6]
at org.eclipse.jetty.server.handler.ContextHandler.doHandle(ContextHandler.java:1129) [jetty-server-9.2.15.v20160210.jar:9.2.15.v20160210]
at org.eclipse.jetty.server.handler.ContextHandler.doScope(ContextHandler.java:1065) [jetty-server-9.2.15.v20160210.jar:9.2.15.v20160210]
at org.eclipse.jetty.server.handler.ScopedHandler.handle(ScopedHandler.java:141) [jetty-server-9.2.15.v20160210.jar:9.2.15.v20160210]
at org.eclipse.jetty.server.handler.ContextHandlerCollection.handle(ContextHandlerCollection.java:215) [jetty-server-9.2.15.v20160210.jar:9.2.15.v20160210]
at org.eclipse.jetty.server.handler.HandlerWrapper.handle(HandlerWrapper.java:97) [jetty-server-9.2.15.v20160210.jar:9.2.15.v20160210]
at org.eclipse.jetty.server.Server.handle(Server.java:499) [jetty-server-9.2.15.v20160210.jar:9.2.15.v20160210]
at org.eclipse.jetty.server.HttpChannel.handle(HttpChannel.java:311) [jetty-server-9.2.15.v20160210.jar:9.2.15.v20160210]
at org.eclipse.jetty.server.HttpConnection.onFillable(HttpConnection.java:257) [jetty-server-9.2.15.v20160210.jar:9.2.15.v20160210]
at org.eclipse.jetty.io.AbstractConnection$2.run(AbstractConnection.java:544) [jetty-io-9.2.15.v20160210.jar:9.2.15.v20160210]
at org.eclipse.jetty.util.thread.QueuedThreadPool.runJob(QueuedThreadPool.java:635) [jetty-util-9.2.15.v20160210.jar:9.2.15.v20160210]
at org.eclipse.jetty.util.thread.QueuedThreadPool$3.run(QueuedThreadPool.java:555) [jetty-util-9.2.15.v20160210.jar:9.2.15.v20160210]
at java.lang.Thread.run(Thread.java:745) [na:1.8.0_91]
16-06-22 19:12:36 [D] [HttpConnection.java:657] org.eclipse.jetty.server.HttpConnection$SendCallback@5b033b51[PROCESSING][i=ResponseInfo{HTTP/1.1 200 null,-1,false},cb=org.eclipse.jetty.server.HttpChannel$CommitCallback@1cb2eb9d] generate: NEED_HEADER (null,[p=0,l=0,c=0,r=0],false)@START
16-06-22 19:12:36 [D] [HttpConnection.java:657] org.eclipse.jetty.server.HttpConnection$SendCallback@5b033b51[PROCESSING][i=ResponseInfo{HTTP/1.1 200 null,-1,false},cb=org.eclipse.jetty.server.HttpChannel$CommitCallback@1cb2eb9d] generate: FLUSH ([p=0,l=117,c=8192,r=117],[p=0,l=0,c=0,r=0],false)@COMMITTED
16-06-22 19:12:36 [D] [WriteFlusher.java:295] write: WriteFlusher@40c8dabd{IDLE} [HeapByteBuffer@e0d40e5[p=0,l=117,c=8192,r=117]={<<<HTTP/1.1 200 OK\r\n....v20160210)\r\n\r\n>>>\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00...\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00}]
16-06-22 19:12:36 [D] [WriteFlusher.java:118] update WriteFlusher@40c8dabd{WRITING}:IDLE-->WRITING
16-06-22 19:12:36 [D] [ChannelEndPoint.java:188] flushed 117 SelectChannelEndPoint@7f7a6aa3{/127.0.0.1:58021<->18085,Open,in,out,-,W,6543/200000,HttpConnection}{io=0,kio=0,kro=1}
16-06-22 19:12:36 [D] [WriteFlusher.java:118] update WriteFlusher@40c8dabd{IDLE}:WRITING-->IDLE
16-06-22 19:12:36 [D] [HttpConnection.java:657] org.eclipse.jetty.server.HttpConnection$SendCallback@5b033b51[PROCESSING][i=ResponseInfo{HTTP/1.1 200 null,-1,false},cb=org.eclipse.jetty.server.HttpChannel$CommitCallback@1cb2eb9d] generate: DONE ([p=117,l=117,c=8192,r=0],[p=0,l=0,c=0,r=0],false)@COMMITTED
16-06-22 19:12:36 [D] [Server.java:502] RESPONSE /eemediation-ws/EEMediationServicePort 200 handled=true
16-06-22 19:12:36 [D] [HttpChannelState.java:289] HttpChannelState@da912da{s=DISPATCHED i=true a=null} unhandle DISPATCHED
16-06-22 19:12:36 [D] [HttpConnection.java:657] org.eclipse.jetty.server.HttpConnection$SendCallback@5b033b51[PROCESSING][i=null,cb=Blocker@3b2f9996{null}] generate: CONTINUE (null,[p=0,l=0,c=0,r=0],true)@COMPLETING
16-06-22 19:12:36 [D] [HttpConnection.java:657] org.eclipse.jetty.server.HttpConnection$SendCallback@5b033b51[PROCESSING][i=null,cb=Blocker@3b2f9996{null}] generate: NEED_CHUNK (null,[p=0,l=0,c=0,r=0],true)@COMPLETING
16-06-22 19:12:36 [D] [HttpConnection.java:657] org.eclipse.jetty.server.HttpConnection$SendCallback@5b033b51[PROCESSING][i=null,cb=Blocker@3b2f9996{null}] generate: FLUSH (null,[p=0,l=0,c=0,r=0],true)@COMPLETING
16-06-22 19:12:36 [D] [WriteFlusher.java:295] write: WriteFlusher@40c8dabd{IDLE} [HeapByteBuffer@44cb4d4a[p=0,l=5,c=1024,r=5]={<<<0\r\n\r\n>>>\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00...\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00}]
16-06-22 19:12:36 [D] [WriteFlusher.java:118] update WriteFlusher@40c8dabd{WRITING}:IDLE-->WRITING
16-06-22 19:12:36 [D] [ChannelEndPoint.java:188] flushed 5 SelectChannelEndPoint@7f7a6aa3{/127.0.0.1:58021<->18085,Open,in,out,-,W,3/200000,HttpConnection}{io=0,kio=0,kro=1}
16-06-22 19:12:36 [D] [WriteFlusher.java:118] update WriteFlusher@40c8dabd{IDLE}:WRITING-->IDLE
16-06-22 19:12:36 [D] [HttpConnection.java:657] org.eclipse.jetty.server.HttpConnection$SendCallback@5b033b51[PROCESSING][i=null,cb=Blocker@3b2f9996{null}] generate: DONE (null,[p=0,l=0,c=0,r=0],true)@END
16-06-22 19:12:36 [D] [HttpConnection.java:373] unconsumed input HttpConnection@3359b3ac[FILLING,SelectChannelEndPoint@7f7a6aa3{/127.0.0.1:58021<->18085,Open,in,out,-,-,1/200000,HttpConnection}{io=0,kio=0,kro=1}][p=HttpParser{s=CONTENT,877 of 877},g=HttpGenerator{s=END},c=HttpChannelOverHttp@38d29a84{r=1,c=true,a=COMPLETED,uri=/eemediation-ws/EEMediationServicePort}]
16-06-22 19:12:36 [D] [HttpParser.java:1232] parseNext s=CONTENT HeapByteBuffer@9b849ba[p=1229,l=1229,c=8192,r=0]={POST /eemediation...apenv:Envelope><<<>>>\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00...\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00}
16-06-22 19:12:36 [D] [HttpParser.java:1587] CONTENT --> END
16-06-22 19:12:36 [D] [HttpChannel.java:705] HttpChannelOverHttp@38d29a84{r=1,c=true,a=COMPLETED,uri=/eemediation-ws/EEMediationServicePort} messageComplete
16-06-22 19:12:36 [D] [HttpInput.java:272] HttpInputOverHTTP@4b5e5f5a EOF
16-06-22 19:12:36 [D] [ChannelEndPoint.java:142] filled 0 SelectChannelEndPoint@7f7a6aa3{/127.0.0.1:58021<->18085,Open,in,out,-,-,2/200000,HttpConnection}{io=0,kio=0,kro=1}
16-06-22 19:12:36 [D] [HttpConnection.java:322] HttpConnection@3359b3ac[FILLING,SelectChannelEndPoint@7f7a6aa3{/127.0.0.1:58021<->18085,Open,in,out,-,-,3/200000,HttpConnection}{io=0,kio=0,kro=1}][p=HttpParser{s=END,877 of 877},g=HttpGenerator{s=END},c=HttpChannelOverHttp@38d29a84{r=1,c=true,a=COMPLETED,uri=/eemediation-ws/EEMediationServicePort}] filled 0
16-06-22 19:12:36 [D] [HttpInput.java:151] HttpInputOverHTTP@4b5e5f5a eof EOF
16-06-22 19:12:36 [D] [HttpParser.java:1563] reset HttpParser{s=END,877 of 877}
16-06-22 19:12:36 [D] [HttpParser.java:1587] END --> START
16-06-22 19:12:36 [D] [HttpChannel.java:448] HttpChannelOverHttp@38d29a84{r=1,c=false,a=IDLE,uri=} handle exit, result COMPLETE
16-06-22 19:12:36 [D] [ChannelEndPoint.java:142] filled 0 SelectChannelEndPoint@7f7a6aa3{/127.0.0.1:58021<->18085,Open,in,out,-,-,6/200000,HttpConnection}{io=0,kio=0,kro=1}
16-06-22 19:12:36 [D] [ChannelEndPoint.java:142] filled 0 SelectChannelEndPoint@7f7a6aa3{/127.0.0.1:58021<->18085,Open,in,out,-,-,6/200000,HttpConnection}{io=0,kio=0,kro=1}
16-06-22 19:12:36 [D] [HttpParser.java:1232] parseNext s=START HeapByteBuffer@e0d40e5[p=0,l=0,c=8192,r=0]={<<<>>>HTTP/1.1 200 OK\r\n...\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00}
16-06-22 19:12:36 [D] [AbstractConnection.java:128] fillInterested HttpConnection@3359b3ac[FILLING,SelectChannelEndPoint@7f7a6aa3{/127.0.0.1:58021<->18085,Open,in,out,-,-,7/200000,HttpConnection}{io=0,kio=0,kro=1}][p=HttpParser{s=START,0 of -1},g=HttpGenerator{s=START},c=HttpChannelOverHttp@38d29a84{r=1,c=false,a=IDLE,uri=}]
16-06-22 19:12:36 [D] [AbstractConnection.java:275] FILLING-->FILLING_FILL_INTERESTED HttpConnection@3359b3ac[FILLING_FILL_INTERESTED,SelectChannelEndPoint@7f7a6aa3{/127.0.0.1:58021<->18085,Open,in,out,-,-,7/200000,HttpConnection}{io=0,kio=0,kro=1}][p=HttpParser{s=START,0 of -1},g=HttpGenerator{s=START},c=HttpChannelOverHttp@38d29a84{r=1,c=false,a=IDLE,uri=}]
16-06-22 19:12:36 [D] [AbstractConnection.java:275] FILLING_FILL_INTERESTED-->FILL_INTERESTED HttpConnection@3359b3ac[FILL_INTERESTED,SelectChannelEndPoint@7f7a6aa3{/127.0.0.1:58021<->18085,Open,in,out,-,-,8/200000,HttpConnection}{io=0,kio=0,kro=1}][p=HttpParser{s=START,0 of -1},g=HttpGenerator{s=START},c=HttpChannelOverHttp@38d29a84{r=1,c=false,a=IDLE,uri=}]
16-06-22 19:12:36 [D] [SelectChannelEndPoint.java:136] Local interests updating 0 -> 1 for SelectChannelEndPoint@7f7a6aa3{/127.0.0.1:58021<->18085,Open,in,out,R,-,0/200000,HttpConnection}{io=1,kio=0,kro=1}
16-06-22 19:12:36 [D] [SelectorManager.java:480] Queued change org.eclipse.jetty.io.SelectChannelEndPoint$1@3cfd9e43
16-06-22 19:12:36 [D] [SelectorManager.java:602] Selector loop woken up from select, 0/1 selected
16-06-22 19:12:36 [D] [SelectorManager.java:525] Running change org.eclipse.jetty.io.SelectChannelEndPoint$1@3cfd9e43
16-06-22 19:12:36 [D] [SelectChannelEndPoint.java:160] Key interests updated 0 -> 1 on SelectChannelEndPoint@7f7a6aa3{/127.0.0.1:58021<->18085,Open,in,out,R,-,2/200000,HttpConnection}{io=1,kio=1,kro=1}
16-06-22 19:12:36 [D] [SelectorManager.java:599] Selector loop waiting on select
答案 0 :(得分:2)
我可以使用JAX-RS和JAX-WS重现您的问题。似乎从CXF拦截器抛出的异常会逃避JAX-RS / JAX-WS流并且未正确处理。有关客户端的类似案例,请参阅我在Propagate exception from CXF interceptor to exception mapper的回复。
interceptor.handleMessage
处的RuntimeException生成一个Fault,响应代码为:
interceptor.handleFault
处的RuntimeException生成一个错误,响应代码为:
- 如果您的服务方法最初返回200,则为200.无效的正文。收到SoapFault但XML无效
- 如果您的服务方法最初返回其他错误代码,则为200。空身
为什么结果200 OK?
它只能是一个bug。 对于SOAP 1.2,W3C规范指定状态代码为400或500,具体取决于故障类型。见http://www.w3.org/TR/soap12-part2/#tabresstatereccodes
表20为什么身体是空的?
在所有情况下,身体都不是空的。在某些情况下,CXF 3.1.6返回SOAP错误,真正奇怪的是,如果服务回答200,请将正确答案与soap fault连接!
看看我已经执行的真实回复
ID: 1
Response-Code: 200
Encoding: UTF-8
Content-Type: text/xml;charset=UTF-8
Headers: {Content-Length=[199], content-type=[text/xml;charset=UTF-8], Date=[Fri, 01 Jul 2016 06:12:40 GMT], Server=[Apache-Coyote/1.1]}
Payload: <soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/"><soap:Body><ns2:testWSResponse xmlns:ns2="http://test/"><return>name123</return></ns2:testWSResponse></soap:Body></soap:Envelope>
对拦截器的双重调用是有道理的。
1)OutInterceptor1.handleMessage()
- &gt; RuntimeException
2)OutInterceptor1.handleFault()
- &gt;调用,因为handleMessage
生成了Fault
。查看javadoc of Interceptor
void handleFault(T message)
为成功调用handleMessage的所有拦截器(按相反顺序)调用,当链的正常执行因某种原因而中止时。
3)OutFaultInterceptor2.handleMessage()
被调用,因为OutInterceptor1
生成了一个错误。
4)OutFaultInterceptor2.handleFault()
被调用,因为OutFaultInterceptor2.handleMessage()
生成了错误