Java servlet 簡單實現http文件下載斷點續傳功能

斷點續傳,聽上去似乎是個比較高級的話題,本文只講述一下http版的斷點續傳,其他協議的大家可以自行研究。

http協議中,服務端實現斷點續傳首先需要讀取客戶端傳送的Range頭信息,比如“Range: bytes=12583394-這個就是指原來正在下載的文件需要從第12583394字節繼續下載,然後我們利用java.io.File的skip方法,捨棄掉原文件的前n個字節,接着就繼續慢慢write吧。。。

但是客戶端又是如何判斷服務端是否支持斷點續傳的呢?主要就是Accept-Ranges和Content-Length頭信息。比如“Accept-Ranges:bytes”和“Content-Length:99999999”。有了這兩個頭信息,客戶端就認爲服務端是支持斷點續傳的了。

然後需要注意的是,假如客戶端剛纔由於某些原因,暫停了下載,現在恢復的時候,就會如前所述,傳來Range頭信息,這時候,我們的response就需要設置一下狀態碼,這裏應該設置成206(詳細解釋請看http://en.wikipedia.org/wiki/List_of_HTTP_status_codes),還有就是Content-Range頭信息,格式爲“bytes x-(y-1)/y”,x就是客戶端傳來的開始字節位置,y就是文件長度。

理解了這些,再看看給出的實例代碼,實現起來就是十分簡單了。實例代碼:

01 package test;
02  
03 import java.io.File;
04 import java.io.FileInputStream;
05 import java.io.IOException;
06 import java.io.OutputStream;
07  
08 import javax.servlet.ServletException;
09 import javax.servlet.http.HttpServlet;
10 import javax.servlet.http.HttpServletRequest;
11 import javax.servlet.http.HttpServletResponse;
12  
13 public class DownloadTestServlet extends HttpServlet {
14     @Override
15     protected void doGet(HttpServletRequest req, HttpServletResponse resp)
16             throws ServletException, IOException {
17         // TODO Auto-generated method stub
18         doPost(req, resp);
19     }
20  
21     @Override
22     protected void doPost(HttpServletRequest req, HttpServletResponse resp)
23             throws ServletException, IOException {
24         resp.reset();
25         long pos = 0;
26         String fileName = req.getParameter("file");
27         System.out.println("The file is:" + fileName);
28         OutputStream os = null;
29         FileInputStream is = null;
30         try {
31             File f = new File("D:\\xx\\" + fileName);
32             is = new FileInputStream(f);
33             long fSize = f.length();
34             byte xx[] = new byte[4096];
35             resp.setHeader("Accept-Ranges", "bytes");
36             resp.setHeader("Content-Length", fSize + "");
37             resp.setHeader("Content-Disposition", "attachment;filename="
38                     + fileName);
39             if (req.getHeader("Range") != null) {
40                 // 若客戶端傳來Range,說明之前下載了一部分,設置206狀態(SC_PARTIAL_CONTENT)
41                 resp.setStatus(HttpServletResponse.SC_PARTIAL_CONTENT);
42                 pos = Long.parseLong(req.getHeader("Range")
43                         .replaceAll("bytes=", "").replaceAll("-", ""));
44             }
45             if (pos != 0) {
46                 String contentRange = new StringBuffer("bytes ")
47                         .append(new Long(pos).toString()).append("-")
48                         .append(new Long(fSize - 1).toString()).append("/")
49                         .append(new Long(fSize).toString()).toString();
50                 resp.setHeader("Content-Range", contentRange);
51                 System.out.println("Content-Range=" + contentRange);
52                 // 略過已經傳輸過的字節
53                 is.skip(pos);
54             }
55             os = resp.getOutputStream();
56             boolean all = false;
57             while (!all) {
58                 int n = is.read(xx);
59                 if (n != -1) {
60                     os.write(xx, 0, n);
61                 } else {
62                     all = true;
63                 }
64             }
65         } catch (IOException e) {
66             e.printStackTrace();
67             return;
68         } finally {
69             if (is != null)
70                 is.close();
71             if (os != null)
72                 os.close();
73         }
74     }
75 }

本實例代碼使用ff測試通過,但用360和the world等自帶的下載工具不能續傳,原因正在查找,歡迎討論~

*******************************************

@ 2010-11-30 21:29

不知道爲何就是不支持ie內核的瀏覽器自帶的下載工具進行斷點續傳。。。自行模擬ie內核瀏覽器客戶端,發完全一樣的http header到servlet,明顯能順利斷點續傳,初步估計是瀏覽器處理問題,最值得懷疑的是“Connection:close”,用ff,chrome,opera都沒有問題,都是keep-alive,求高手回答~!


轉自:http://www.shaojiahao.org/tag/%E6%96%AD%E7%82%B9%E7%BB%AD%E4%BC%A0



發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章