2010-06-01 48 views
4

我偶爾從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"); 
     } 
    } 
+0

相關主題:http://stackoverflow.com/search?q=clientabortexception – BalusC 2010-06-01 23:04:20

回答

2

我懷疑客戶端(瀏覽器)的字節數組到插座的寫作過程中斷開。

+0

處理此問題的正確方法是什麼?捕獲所有IOExceptions? – 2010-06-01 21:50:49

+0

我會那樣做,是的。 – 2010-06-01 21:53:28

+5

你可以抓住它,但你不能以任何明智的方式處理它。您無法恢復響應,也無法將任何位寫入客戶端。你可以在最高的日誌。但這些信息有多有用?客戶只是決定放棄下載或導航,或者網絡出去了,或者它的PC崩潰了。對於統計來說很有趣,但實際上並不僅限於此。 – BalusC 2010-06-01 23:02:08

0

嘗試蒐集更多有關環境時,此異常情況,並記錄它。

正常情況下,日誌字節數組大小和HTTP請求中的「User-Agent」字段,並且在引發異常時明確記錄此信息。

可能是因爲字節數組太大而無法在一次寫入中寫入,而且您可能需要將其分成幾塊。

另外,我建議你看看commons-fileupload。即使你沒有在你的項目中使用它,瀏覽源代碼並查看他們如何下載文件。他們在文件上傳過程中曾經有很多IOException,但是在更高版本中已經修復了這些問題。你可能試圖弄清楚究竟是什麼修復了。

+0

在Java的任何地方都沒有這樣的事情,'一個字節數組太大而無法在一次傳遞中寫入'。 並且此輸出流已被分塊,請參閱堆棧跟蹤。 – EJP 2010-06-02 03:48:52

+0

@EJP。是的,我知道,但Java抽象和真實世界是兩回事。 – 2010-06-02 11:15:08

+0

無意義的評論。我再說一遍,沒有太大的字節數組無法在Java中的任何地方編寫。如果您有相反的證據,請提供。我們正在討論在這裏阻塞I/O,它循環直到寫入完成或發生異常。 – EJP 2010-06-02 23:58:34

1

如果客戶端斷開連接(即取消下載或關閉瀏覽器),您將得到一個IOException

如果這不是你的應用程序的終端問題,這可能是這種情況,那麼你應該抓住這個異常,什麼也不做。如果您想收集關於下載被客戶端中止的頻率的統計信息,您可以做一些日誌記錄。

2

處理這個問題的正確方法是什麼?捕獲所有IOExceptions?

捕獲所有的IOExceptions是合理的,但下面是狡猾的:

catch (Base64DecodingException e) { 
     e.printStackTrace(); 
     response.getOutputStream().print("An error occurred"); 
    } 

首先,你應該使用一個日誌框架(如log4j的),而不是通過調用e.printStackTrace()寫的診斷標準錯誤。

其次,寫入類似於響應輸出的錯誤消息可能是錯誤的。

  • 該消息是無效的。
  • 客戶端在此時不會期待錯誤消息。
  • 如果需要錯誤消息,則客戶端將無法區分錯誤消息和真實數據......而無需知道所有服務器錯誤消息的硬件知識。

向HTTP客戶端報告錯誤的首選方法是在HTTP響應中設置4xx或5xx狀態碼,並且(理想情況下)設置錯誤消息。但是,如果響應沒有「提交」,則只能執行此操作,並且打開響應輸出流將提交響應。

最後,您不能採取這種方法,通常將錯誤消息寫入客戶端以處理I/O異常。如果I/O異常指示輸出連接中斷,則向響應流寫入消息只會引發另一個異常。