Java/Jetty/Wildfly:优雅地处理中止的客户端连接
Java/Jetty/Wildfly: Gracefully Handle Aborted Client Connections
我开发了一个播放音频和视频文件的网络应用程序。用户可以更改当前播放的曲目,在这种情况下,客户端会为 HTML 5 播放器设置新的来源。应用的分发使用嵌入式Jetty 9,其他环境运行 WildFly 8.
应用程序正常工作,但是当用户更改曲目时,WildFly 会发出此堆栈跟踪:
java.io.IOException: An established connection was aborted by the software in your host machine
at sun.nio.ch.SocketDispatcher.writev0(Native Method) [rt.jar:1.7.0_75]
at sun.nio.ch.SocketDispatcher.writev(SocketDispatcher.java:55) [rt.jar:1.7.0_75]
at sun.nio.ch.IOUtil.write(IOUtil.java:148) [rt.jar:1.7.0_75]
at sun.nio.ch.SocketChannelImpl.write(SocketChannelImpl.java:524) [rt.jar:1.7.0_75]
at org.xnio.nio.NioSocketConduit.write(NioSocketConduit.java:161)
at io.undertow.server.protocol.http.HttpResponseConduit.write(HttpResponseConduit.java:609) [undertow-core-1.1.0.Final.jar:1.1.0.Final]
at io.undertow.conduits.AbstractFixedLengthStreamSinkConduit.write(AbstractFixedLengthStreamSinkConduit.java:148) [undertow-core-1.1.0.Final.jar:1.1.0.Final]
...
并且 Jetty 抛出类似的错误:
org.eclipse.jetty.io.EofException
at org.eclipse.jetty.io.ChannelEndPoint.flush(ChannelEndPoint.java:192)
at org.eclipse.jetty.io.WriteFlusher.flush(WriteFlusher.java:408)
at org.eclipse.jetty.io.WriteFlusher.write(WriteFlusher.java:302)
at org.eclipse.jetty.io.AbstractEndPoint.write(AbstractEndPoint.java:128)
...
Caused by: java.io.IOException: Broken pipe
at sun.nio.ch.FileDispatcherImpl.write0(Native Method)
at sun.nio.ch.SocketDispatcher.write(SocketDispatcher.java:47)
at sun.nio.ch.IOUtil.writeFromNativeBuffer(IOUtil.java:93)
at sun.nio.ch.IOUtil.write(IOUtil.java:65)
有道理 - 是的,客户端中止了与前一个源文件的连接并发出了下一个文件的 GET 请求,但这是应用程序的预期操作。
有没有办法优雅地处理这个问题并避免这些错误?
如果异常是从您的应用程序正在进行的调用内部抛出的,请捕获 IOException 并按您希望的方式处理它 - 可能是从您的代码正在执行的任何操作中返回而不抱怨。
Tomcat 有 org.apache.catalina.connector.ClientAbortException 所以你可以分辨这个和其他 IOException 之间的区别,但是没有 Servlet 规范定义的可移植异常。
如果异常发生在纯容器代码中,例如 IO 工作线程,那么我会提交一个 bug,指出预计会发生客户端断开连接,因此不应在高于 [=16 的任何位置记录异常=] 等级.
我开发了一个播放音频和视频文件的网络应用程序。用户可以更改当前播放的曲目,在这种情况下,客户端会为 HTML 5 播放器设置新的来源。应用的分发使用嵌入式Jetty 9,其他环境运行 WildFly 8.
应用程序正常工作,但是当用户更改曲目时,WildFly 会发出此堆栈跟踪:
java.io.IOException: An established connection was aborted by the software in your host machine
at sun.nio.ch.SocketDispatcher.writev0(Native Method) [rt.jar:1.7.0_75]
at sun.nio.ch.SocketDispatcher.writev(SocketDispatcher.java:55) [rt.jar:1.7.0_75]
at sun.nio.ch.IOUtil.write(IOUtil.java:148) [rt.jar:1.7.0_75]
at sun.nio.ch.SocketChannelImpl.write(SocketChannelImpl.java:524) [rt.jar:1.7.0_75]
at org.xnio.nio.NioSocketConduit.write(NioSocketConduit.java:161)
at io.undertow.server.protocol.http.HttpResponseConduit.write(HttpResponseConduit.java:609) [undertow-core-1.1.0.Final.jar:1.1.0.Final]
at io.undertow.conduits.AbstractFixedLengthStreamSinkConduit.write(AbstractFixedLengthStreamSinkConduit.java:148) [undertow-core-1.1.0.Final.jar:1.1.0.Final]
...
并且 Jetty 抛出类似的错误:
org.eclipse.jetty.io.EofException
at org.eclipse.jetty.io.ChannelEndPoint.flush(ChannelEndPoint.java:192)
at org.eclipse.jetty.io.WriteFlusher.flush(WriteFlusher.java:408)
at org.eclipse.jetty.io.WriteFlusher.write(WriteFlusher.java:302)
at org.eclipse.jetty.io.AbstractEndPoint.write(AbstractEndPoint.java:128)
...
Caused by: java.io.IOException: Broken pipe
at sun.nio.ch.FileDispatcherImpl.write0(Native Method)
at sun.nio.ch.SocketDispatcher.write(SocketDispatcher.java:47)
at sun.nio.ch.IOUtil.writeFromNativeBuffer(IOUtil.java:93)
at sun.nio.ch.IOUtil.write(IOUtil.java:65)
有道理 - 是的,客户端中止了与前一个源文件的连接并发出了下一个文件的 GET 请求,但这是应用程序的预期操作。
有没有办法优雅地处理这个问题并避免这些错误?
如果异常是从您的应用程序正在进行的调用内部抛出的,请捕获 IOException 并按您希望的方式处理它 - 可能是从您的代码正在执行的任何操作中返回而不抱怨。
Tomcat 有 org.apache.catalina.connector.ClientAbortException 所以你可以分辨这个和其他 IOException 之间的区别,但是没有 Servlet 规范定义的可移植异常。
如果异常发生在纯容器代码中,例如 IO 工作线程,那么我会提交一个 bug,指出预计会发生客户端断开连接,因此不应在高于 [=16 的任何位置记录异常=] 等级.