【SpringMVC(十五)】HttpRange 分片下载 断点续传

32 篇文章 15 订阅
30 篇文章 5 订阅

基于http协议实现断点续传。

请求部分,需要在请求头里加入Range头,表示本次请求的byte数组的开始和结束位置。

https://tools.ietf.org/html/rfc7233#section-3.1

格式为:Bytes=开始-结束。如果不填表示0或者最后。

对于要支持断点续传的服务器,需要处理这个请求头,如果发现有Range头部,需要对响应特殊处理。

body:返回Range范围内的字节;

code:返回206;

header:需要返回如下几个header:

  • Content-Range: bytes 0-10/3103,格式为bytes 开始-结束/全部
  • Content-Type,对于二进制数据是application/octet-stream
  • Content-Length: 11,本次内容的大小
  • Accept-Ranges:bytes,表示支持Range请求

例子:

@RestController
@RequestMapping("/rest/n/testApi")
public class DownLoadController implements ApplicationContextAware {

    private ApplicationContext applicationContext;

    @RequestMapping("/download")
    public ResponseEntity<byte[]> download(HttpServletRequest  httpServletRequest,
             @RequestParam String fileName) throws IOException {
        Resource classPathResource = applicationContext.getResource("classpath:" + filePath(fileName));
        byte[] bytes = IOUtils.toByteArray(classPathResource.getInputStream());
        return doDownload(httpServletRequest, bytes);
    }

    private ResponseEntity<byte[]> doDownload(HttpServletRequest  httpServletRequest, byte[] bytes) {
        String ranges = httpServletRequest.getHeader(HttpHeaders.RANGE);
        HttpHeaders headers = new HttpHeaders();
        headers.setContentType(MediaType.APPLICATION_OCTET_STREAM);
        return StringUtils.isEmpty(ranges) ?
                fullDownload(headers, bytes) : rangeDownload(headers, ranges, bytes);
    }

    private ResponseEntity<byte[]> rangeDownload(HttpHeaders headers, String ranges, byte[] bytes) {
        HttpRange httpRange = getHttpRange(ranges);
        byte[] rangedBytes = ArrayUtils.subarray(bytes,
                (int)httpRange.getRangeStart(bytes.length), (int)httpRange.getRangeEnd(bytes.length) + 1);
        headers.add(HttpHeaders.ACCEPT_RANGES, "bytes");
        headers.add(HttpHeaders.CONTENT_RANGE, createContentRange(httpRange, bytes.length));
        headers.setContentLength(rangedBytes.length);
        return new ResponseEntity<>(rangedBytes, headers, HttpStatus.PARTIAL_CONTENT);
    }

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        this.applicationContext = applicationContext;
    }

}

传入文件名,在classpath下查找并返回文件。读取文件使用了Spring框架的Resource接口。

download接口的返回类型定义为ResponseEntity,方便处理response的header以及status。

几个工具类:

public class FileDownloadUtil {

    public static String filePath(String name) {
        return "static/files/" + name + ".txt";
    }

    public static HttpRange getHttpRange(String range) {
        String[] ranges = range.substring(range.indexOf("=") + 1).split("-");
        return HttpRange.createByteRange(toLong(ranges[0]), toLong(ranges[1]));
    }

    public static String createContentRange(HttpRange httpRange, long length) {
        return "bytes" + httpRange.getRangeEnd(length) + "-" + httpRange.getRangeEnd(length) + "/" + length;
    }

}

 

resources/static/file/a.txt文件内容:

hello

请求一:

curl -H 'Range: bytes=0-1' 'http://localhost:8080/rest/n/testApi/download?fileName=a'
he

请求二:

curl -H 'Range: bytes=2-4' 'http://localhost:8080/rest/n/testApi/download?fileName=a'
llo

 

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值