2010-01-14 72 views
5

我有一個servlet允許用戶從網頁下載(可能很大)的zip文件。如果用戶點擊一個鏈接,下載一個壓縮文件,類似的代碼在servlet中執行以下操作:Java Servlets:當用戶離開頁面時文件下載中斷

response.setContentType("application/zip"); 
response.setHeader("Content-disposition", "attachment; filename=foo.zip"); 
response.setHeader("Pragma", ""); 
response.setHeader("Cache-Control", "no-store"); 

ZipOutputStream out = new ZipOutputStream(response.getOutputStream()); 
// write entries to the zip file... 
... 
out.close() 

但是,如果用戶刷新或退出下載後離開當前頁面開始之前它完成(在Firefox 3.5.7中),下載將失敗。以下錯誤彈出:

C:\等等\ foo.zip.part不能 保存,因爲源文件可能 無法讀取。

稍後重試,或聯繫服務器 管理員。

關於如何確保下載在這種情況下繼續的任何想法?

UPDATE:啓動下載的鏈接是普通的香草鏈接。有趣的是,IE的行爲不同。點擊網站上其他地方的鏈接(來自當前加載的屏幕)似乎無法加載(瀏覽器狀態欄顯示「正在等待https://mysite/clicked_linky.do ...」),直到下載完成。在地址欄中鍵入不同的URL或使用快捷方式/收藏夾鏈接可導航離開頁面,但下載會按預期繼續。只有Firefox似乎顯示了我上面描述的確切行爲,儘管IE阻止並不是最優的。

回答

6

這應該實際上不會發生。下載計爲單獨的請求,它應該在調用後獨立於父頁面在後臺運行。你究竟如何觸發下載請求?通過普通的香草鏈接或鏈接(錯誤地)發出ajaxical請求來運行下載?

無論如何,您至少明確希望能夠簡歷下載。在這種情況下,您需要至少沿着下載發送至少Accept-RangesETagLast-Modified響應標題。然後,客戶端可以通過發送If-RangeRange請求標頭,分別指定文件標識符和指定的字節範圍,然後結合使用RandomAccessFile來發送剩餘的字節,從而請求恢復下載。您可以在this article中找到更多信息和servlet示例。

這就是理論。在你的特定情況下,當你在運行中壓縮文件時,它有點詭計。您需要首先將zip文件寫入服務器本地磁盤文件系統的臨時文件夾中,然後從中進行流式處理,最後在下載成功完成時(即out.close()未拋出IOException)刪除文件只有。您可以藉助請求參數或pathinfo或會話中的密鑰來識別關聯的zip文件。

更新:根據您的更新:我真的不知道,我從來沒有經歷過,但至少我可以告訴you're not the only one who suffered from this problem。至少,執行如前所述的恢復功能可能是解決這一特定問題的解決方案,因爲Firefox隨後會自動恢復下載,而不會對不完整的部分產生不滿。

更新2:讀您的更新和瀏覽器行爲後有一個小的想法後,它看起來像有射擊的實際請求和響應頭到達之間相當巨大的時間間隔。我不知道你如何加載文件的確切細節,但它看起來像這樣收集ZIP文件需要一定的時間成本(也許你預先從網絡文件系統或數據庫加載它們),並且你設置/發送應答頭你已經收集了所有的ZIP文件。嘗試設置標題並在執行昂貴的任務之前執行output.flush()。通過這種方式,瀏覽器將盡快獲得標題,它將知道它可能會有什麼期望。

+0

我同意,一個獨立的下載servlet請求應如果客戶端將瀏覽器帶到另一個頁面或刷新,那麼不會搞砸了,我已經在Java中實現了一個下載servlet,並且沒有遇到任何這些問題 – 2010-01-14 21:23:00

+0

這是一個普通的香草鏈接,我更新了問題。 – Jeff 2010-01-14 21:39:55

0

我懷疑這是使用servlet的一種假象 - 可能是因爲重新分配了該線程。當然,我沒有這樣的問題,用PHP編寫的(每個請求由(有效)的新工藝處理類似的設置。

HTH

C.