Servlet的IOException异常流字节数组
我偶尔从Servlet我有,为了提供文件下载功能写入字节数组的OutputStream获得一个IOException时。Servlet的IOException异常流字节数组
这个下载的servlet流量合理(每月点击10万次),这种情况很少出现,大约每月1-2次。
我已经尝试通过使用完全相同的Base64字符串来重新创建异常,并且不会引发异常,并且Servlet的行为与设计相同。
是这个IO异常被超出了我的控制应用程序什么引起的?例如 网络问题或用户重置连接?我试图谷歌在这个堆栈中的IOException的原因,但无济于事。
环境正在运行Tomcat 5.5在CentOS 5.3与Apache HTTP服务器作为使用proxy_ajp代理。
ClientAbortException: java.io.IOException
at org.apache.catalina.connector.OutputBuffer.realWriteBytes(OutputBufferjava:366)
at org.apache.tomcat.util.buf.ByteChunk.append(ByteChunk.java:352)
at org.apache.catalina.connector.OutputBuffer.writeBytes(OutputBuffer.java:392)
at org.apache.catalina.connector.OutputBuffer.write(OutputBuffer.java:381)
at org.apache.catalina.connector.CoyoteOutputStream.write(CoyoteOutputStream.java:89)
at org.apache.catalina.connector.CoyoteOutputStream.write(CoyoteOutputStream.java:83)
at com.myApp.Download.doPost(Download.java:34)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:710)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:803)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:269)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:188)
at org.apache.catalina.core.ApplicationDispatcher.invoke(ApplicationDispatcher.java:691)
at org.apache.catalina.core.ApplicationDispatcher.processRequest(ApplicationDispatcher.java:469)
at org.apache.catalina.core.ApplicationDispatcher.doForward(ApplicationDispatcher.java:403)
at org.apache.catalina.core.ApplicationDispatcher.forward(ApplicationDispatcher.java:301)
at com.myApp.EntryServlet.service(EntryServlet.java:278)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:803)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:269)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:188)
at com.myApp.filters.RequestFilter.doFilter(RequestFilter.java:16)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:215)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:188)
at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:210)
at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:172)
at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:127)
at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:117)
at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:108)
at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:151)
at org.apache.coyote.ajp.AjpAprProcessor.process(AjpAprProcessor.java:444)
at org.apache.coyote.ajp.AjpAprProtocol$AjpConnectionHandler.process(AjpAprProtocol.java:472)
at org.apache.tomcat.util.net.AprEndpoint$Worker.run(AprEndpoint.java:1286)
at java.lang.Thread.run(Thread.java:636)
Caused by: java.io.IOException
at org.apache.coyote.ajp.AjpAprProcessor.flush(AjpAprProcessor.java:1200)
at org.apache.coyote.ajp.AjpAprProcessor$SocketOutputBuffer.doWrite(AjpAprProcessor.java:1285)
at org.apache.coyote.Response.doWrite(Response.java:560)
at org.apache.catalina.connector.OutputBuffer.realWriteBytes(OutputBufferjava:361)
而且在下载的Servlet代码:
@Override
protected void doPost (HttpServletRequest request, HttpServletResponse response) throws ServletException, java.io.IOException {
try {
response.setContentType("application/pdf");
response.setHeader("Pragma", "");
response.setHeader("Cache-Control", "");
response.setHeader("Content-Disposition", "Inline; Filename=myPDFFile..pdf");
ServletOutputStream out = response.getOutputStream();
byte[] downloadBytes = Base64.decode((String)request.getAttribute("fileToDownloadBase64"));
out.write(downloadBytes);
} catch (Base64DecodingException e) {
e.printStackTrace();
response.getOutputStream().print("An error occurred");
}
}
我怀疑客户端(浏览器)的字节数组到插座的写作过程中断开。
处理此问题的正确方法是什么?捕获所有IOExceptions? – 2010-06-01 21:50:49
我会那样做,是的。 – 2010-06-01 21:53:28
你可以抓住它,但你不能以任何明智的方式处理它。您无法恢复响应,也无法将任何位写入客户端。你可以在最高的日志。但这些信息有多有用?客户只是决定放弃下载或导航,或者网络出去了,或者它的PC崩溃了。对于统计来说很有趣,但实际上并不仅限于此。 – BalusC 2010-06-01 23:02:08
尝试搜集更多有关环境时,此异常情况,并记录它。
正常情况下,日志字节数组大小和HTTP请求中的“User-Agent”字段,并且在引发异常时明确记录此信息。
可能是因为字节数组太大而无法在一次写入中写入,而且您可能需要将其分成几块。
另外,我建议你看看commons-fileupload。即使你没有在你的项目中使用它,浏览源代码并查看他们如何下载文件。他们在文件上传过程中曾经有很多IOException,但是在更高版本中已经修复了这些问题。你可能试图弄清楚究竟是什么修复了。
如果客户端断开连接(即取消下载或关闭浏览器),您将得到一个IOException
。
如果这不是你的应用程序的终端问题,这可能是这种情况,那么你应该抓住这个异常,什么也不做。如果您想收集关于下载被客户端中止的频率的统计信息,您可以做一些日志记录。
处理这个问题的正确方法是什么?捕获所有IOExceptions?
捕获所有的IOExceptions是合理的,但下面是狡猾的:
catch (Base64DecodingException e) {
e.printStackTrace();
response.getOutputStream().print("An error occurred");
}
首先,你应该使用一个日志框架(如log4j的),而不是通过调用e.printStackTrace()
写的诊断标准错误。
其次,写入类似于响应输出的错误消息可能是错误的。
- 该消息是无效的。
- 客户端在此时不会期待错误消息。
- 如果需要错误消息,则客户端将无法区分错误消息和真实数据......而无需知道所有服务器错误消息的硬件知识。
向HTTP客户端报告错误的首选方法是在HTTP响应中设置4xx或5xx状态码,并且(理想情况下)设置错误消息。但是,如果响应没有“提交”,则只能执行此操作,并且打开响应输出流将提交响应。
最后,您不能采取这种方法,通常将错误消息写入客户端以处理I/O异常。如果I/O异常指示输出连接中断,则向响应流写入消息只会引发另一个异常。
相关主题:http://*.com/search?q=clientabortexception – BalusC 2010-06-01 23:04:20