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就是文件长度。

理解了这些,再看看给出的实例代码,实现起来就是十分简单了。实例代码:

01package test;
02 
03import java.io.File;
04import java.io.FileInputStream;
05import java.io.IOException;
06import java.io.OutputStream;
07 
08import javax.servlet.ServletException;
09import javax.servlet.http.HttpServlet;
10import javax.servlet.http.HttpServletRequest;
11import javax.servlet.http.HttpServletResponse;
12 
13public 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



  • 0
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值