Java 断点续传以及在线视频播放可选择任一时间播放原理

其实断点续传和视频选择从任一时间开始播放都很简单,本质上都是服务端读取文件的某一个范围返回给客户端,而服务端怎么知道客户端要从哪读到哪,客户端如何知道服务端是否支持断点续传,这就需要了解HTTP的“Range”约定。

客户端首次访问资源时,在请求头中携带range:

#意味读取从0到文件尾的范围
range: bytes=0-

Range头域可以请求实体的一个或者多个子范围,例如:

表示头500个字节:bytes=0-499  
表示第二个500字节:bytes=500-999  
表示最后500个字节:bytes=-500  
表示500字节以后的范围:bytes=500-  
第一个和最后一个字节:bytes=0-0,-1  
同时指定几个范围:bytes=500-600,601-999

如果服务端支持range,那么会先返回206状态码,以及如下响应头,然后再按照Content-Range响应头里设置的范围把文件输出给客户端。

//文件的MIMEType
response.setContentType(MIMEType.getMIMEType("mp4"));
//文件总大小,这里总大小是2000byte
response.setHeader("Content-Length", String.valueOf(2000));
//本次返回的范围与文件总大小,这里是从0到100byte,总大小未2000
response.setHeader("Content-Range", "bytes " + 0 + "-" + 100 + "/" + 2000);
//写死的内容
response.setHeader("Access-Control-Allow-Origin", "*");
//写死的内容
response.setHeader("Accept-Ranges", "bytes");
//206状态码
response.setStatus(HttpServletresponseonse.SC_PARTIAL_CONTENT);

代码如下所示

public void fileOutputStream(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    //目标文件的路径
    String fileAllPath = (String) request.getAttribute("filePath");
    //文件扩展名
    int index = fileAllPath.lastIndexOf(".");
    String suffix = fileAllPath.substring(index + 1);

    //检查是否是Range请求
    if (request.getHeader("Range") != null) {
        //读取文件
        File targetFile = new File(fileAllPath);
        BufferedInputStream in = new BufferedInputStream(new FileInputStream(targetFile));
        Long fileSize = targetFile.length();

        //解析Range
        Map<String, Integer> range = this.analyzeRange(request.getHeader("Range"), fileSize.intValue());

        //设置响应头
        response.setContentType(MIMEType.getMIMEType(suffix));
        response.setHeader("Content-Length", String.valueOf(fileSize.intValue()));
        response.setHeader("Content-Range", "bytes " + range.get("startByte") + "-" + range.get("endByte") + "/" + fileSize.intValue());
        response.setHeader("Access-Control-Allow-Origin", "*");
        response.setHeader("Accept-Ranges", "bytes");
        response.setStatus(HttpServletResponse.SC_PARTIAL_CONTENT);

        //开始输出
        OutputStream os = response.getOutputStream();
        int length = range.get("endByte") - range.get("startByte");
        System.out.println("length:" + length);
        byte[] buffer = new byte[length < 1024 ? length : 1024];
        in.skip(range.get("startByte"));
        int i = in.read(buffer);
        length = length - buffer.length;
        while (i != -1) {
            os.write(buffer, 0, i);
            if (length <= 0) {
                break;
            }
            i = in.read(buffer);
            length = length - buffer.length;
        }
        os.flush();
        //关闭
        os.close();
        in.close();
        return;
    }
}

/**
 * 解析range,解析出起始byte(startByte)和结束byte(endBytes)
 *
 * @param range    请求发来的range
 * @param fileSize 目标文件的大小
 * @return
 */
private Map<String, Integer> analyzeRange(String range, Integer fileSize) {
    String[] split = range.split("-");
    Map<String, Integer> result = new HashMap<>();
    if (split.length == 1) {
        //从xxx长度读取到结尾
        Integer startBytes = new Integer(range.replaceAll("bytes=", "").replaceAll("-", ""));
        result.put("startByte", startBytes);
        result.put("endByte", fileSize - 1);
    } else if (split.length == 2) {
        //从xxx长度读取到yyy长度
        Integer startBytes = new Integer(split[0].replaceAll("bytes=", "").replaceAll("-", ""));
        Integer endBytes = new Integer(split[1].replaceAll("bytes=", "").replaceAll("-", ""));
        result.put("startByte", startBytes);
        result.put("endByte", endBytes > fileSize ? fileSize : endBytes);
    } else {
        logger.info("未识别的range:", range);
    }
    return result;
}

上述代码可以做文件的断点续传,也可以做视频在线播放,不过需要前端配合一个H5播放器

  • 1
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值