浏览器Content-Range断点续传MP4文件

@RequestMapping("/file/get")
public void download(@RequestHeader(value = "origin", defaultValue = "") String origin, @RequestHeader(value = "User-Agent", defaultValue = "") String userAgent, @RequestHeader(value = "Range", defaultValue = "") String range, @RequestParam(value = "filePath", defaultValue = "") String filePath, HttpServletResponse resp) {
    // 参数错误
    if (StringUtils.isEmpty(filePath)) {
        WebUtils.sendError(resp, HttpStatus.BAD_REQUEST_400, "Parameter - `filePath` missing");
        return;
    }
    log.info("range:{} , user-agent:{}", range, userAgent);
    String fileName = new File(fileKey.trim()).getName();
    if (!StringUtils.isEmpty(fileName)) {
    	//添加文件名称
        resp.addHeader("Content-Disposition", String.format("inline; filename=\"%s\"", fileName));
        //根据文件后缀名添加文件类型
        Optional<MediaType> optionalMediaType = MediaTypeFactory.getMediaType(fileName);
        optionalMediaType.ifPresent(mediaType -> resp.addHeader(HttpHeader.CONTENT_TYPE.asString(), mediaType.toString()));
    }
    String rule = WebUtils.getMatchAllowRule(origin, GlobalVar.getInstance().getAllowRules());
    if (null != rule) {
    	//跨域域名英文【,】逗号隔开
        resp.addHeader("Access-Control-Allow-Origin", rule);
        //支持的方法
        resp.addHeader("Access-Control-Allow-Methods", "GET, POST");
        //不允许跨域Cookies等信息
        resp.addHeader("Access-Control-Allow-Credentials", "false");
        //自定义头部
        resp.addHeader("Access-Control-Allow-Headers", "X-Custom-Header");
    }
    shardFile(range, resp);
}
private void shardFile(String rangeStr,String filePath, HttpServletResponse response) {
    // 起始偏移量,可以根据请求参数来设置
    long offset = 0L;
    long length = 102400L;
    File file = new File(filePath);
    long totalSize = file.length();
    if (StringUtils.isNotEmpty(rangeStr)) {
        offset = Long.valueOf(rangeStr.replace("bytes=", "").split("-")[0]);
        // 每次读取的长度,可以根据请求参数或文件大小来设置
        // 检查偏移量和长度是否有效
        if (offset < 0 || offset >= totalSize) {
            response.setStatus(HttpServletResponse.SC_BAD_REQUEST);
            return;
        }
        if (length <= 0 || offset + length > totalSize) {
            length = totalSize - offset;
        }
    }
	//浏览器断点续传,应答状态是206,需要显示设置,不是200,非常重要
    response.setStatus(HttpServletResponse.SC_PARTIAL_CONTENT);
	//返回当前这一次读取的长度,不是文件总大小
    response.addHeader("Content-Length", String.valueOf(length));
	//文件返回方式,bytes
    response.setHeader("Accept-Ranges", "bytes");
	//浏览器探测到后端返回Content-Range,支持断点续传,会立即终止前面一个连接,报错,连接CLOSE,格式 【bytes 开始offset0开始-结束索引(长度-1)+开始索引】/文件总长度
    String newRangStr = new StringBuffer("bytes ").append(offset).append("-").append((offset + length - 1)).append("/").append(totalSize).toString();
    //文件支持断点续传
	ponse.setHeader("Content-Range", newRangStr);
    try (InputStream is = new BufferedInputStream(new FileInputStream(file))) {
        is.skip(offset);
        byte[] buffer = new byte[10240];
        int readSize = buffer.length;
        int sumSize = 0;
        while (true) {
            if (readSize <= 0) {
                break;
            }
            readSize = is.read(buffer, 0, readSize);
            try {
                response.getOutputStream().write(buffer, 0, readSize);
            } catch (IOException e) {
				//报错连接关闭,不用管
            }
            sumSize += readSize;
            if (sumSize + readSize > length) {
                readSize = (int) (length - sumSize);
            } else if (sumSize >= length) {
                break;
            }
        }
    } catch (Exception e) {
        log.warn("写入失败", e);
    }
}

相关推荐

  1. 浏览器Content-Range断点MP4文件

    2024-07-12 17:38:04       23 阅读
  2. 前端实现断点文件

    2024-07-12 17:38:04       46 阅读
  3. 断点功能

    2024-07-12 17:38:04       59 阅读
  4. FTP超大文件下载入库--断点

    2024-07-12 17:38:04       27 阅读
  5. Android Okhttp断点

    2024-07-12 17:38:04       55 阅读

最近更新

  1. docker php8.1+nginx base 镜像 dockerfile 配置

    2024-07-12 17:38:04       67 阅读
  2. Could not load dynamic library ‘cudart64_100.dll‘

    2024-07-12 17:38:04       71 阅读
  3. 在Django里面运行非项目文件

    2024-07-12 17:38:04       58 阅读
  4. Python语言-面向对象

    2024-07-12 17:38:04       69 阅读

热门阅读

  1. CSS基础

    2024-07-12 17:38:04       22 阅读
  2. 动态路由的基本概念

    2024-07-12 17:38:04       21 阅读
  3. Linux系统基础命令有哪些

    2024-07-12 17:38:04       20 阅读
  4. 嵌入式Qt开发C++核心编程知识万字总结

    2024-07-12 17:38:04       28 阅读
  5. linux ssh 远程执行shell 获取返回值

    2024-07-12 17:38:04       21 阅读
  6. WSGI 服务器教程:`execute` 方法解析

    2024-07-12 17:38:04       22 阅读
  7. Scala学习笔记16: 注解

    2024-07-12 17:38:04       18 阅读
  8. vscode使用ssh连接远程服务器

    2024-07-12 17:38:04       15 阅读