SpringBoot中实现大文件分片下载和断点续传功能的完整指南

 更新时间:2025年09月08日 09:15:25   作者:IT界Tony哥  
在Spring Boot中实现大文件分片下载和断点续传功能,需结合HTTP Range协议和文件流处理技术,本文将展示完整的实现方法,有需要的小伙伴可以参考一下

在Spring Boot中实现大文件分片下载和断点续传功能,需结合HTTP Range协议和文件流处理技术。以下是完整实现方案:

​​一、核心原理​​

​HTTP Range协议​

通过Range请求头指定下载范围(如Range: bytes=0-999),服务器返回206 Partial Content状态码及对应内容片段。

​断点续传机制​

客户端记录已下载的字节范围,网络中断后通过Range头续传未完成部分。

​​二、服务端实现​​

​​1. 分片下载接口​​

@GetMapping("/download")
public ResponseEntity<InputStreamResource> downloadFile(
    @RequestHeader(value = "Range", required = false) String rangeHeader,
    HttpServletRequest request) throws IOException {
    
    // 获取文件信息
    File file = new File("/path/to/largefile.zip");
    long fileSize = file.length();
    
    // 解析Range头
    long start = 0, end = fileSize - 1;
    if (rangeHeader != null) {
        String[] ranges = rangeHeader.replace("bytes=", "").split("-");
        start = Long.parseLong(ranges[0]);
        if (ranges.length > 1) {
            end = Long.parseLong(ranges[1]);
        }
    }
    
    // 校验范围合法性
    if (start >= fileSize || end >= fileSize || start > end) {
        return ResponseEntity.status(HttpStatus.REQUESTED_RANGE_NOT_SATISFIABLE)
                .header("Content-Range", "bytes */" + fileSize)
                .build();
    }
    
    // 设置响应头
    HttpHeaders headers = new HttpHeaders();
    headers.setContentType(MediaType.APPLICATION_OCTET_STREAM);
    headers.setContentLength(end - start + 1);
    headers.setHeader("Content-Range", "bytes " + start + "-" + end + "/" + fileSize);
    headers.setHeader("Accept-Ranges", "bytes");
    
    // 返回分片数据流
    try (InputStream is = new FileInputStream(file);
         InputStreamResource resource = new InputStreamResource(is)) {
        is.skip(start);
        return new ResponseEntity<>(resource, headers, HttpStatus.PARTIAL_CONTENT);
    }
}

​​2. 断点续传支持​​

​客户端记录进度​​:保存已下载的字节范围(如0-999)。

​续传请求​​:重新发起请求时携带Range: bytes=1000-,服务器从断点处继续传输。

​​三、客户端实现(JavaScript示例)​​

// 分片下载逻辑
async function downloadFileWithResume(fileId, fileName) {
  const CHUNK_SIZE = 5 * 1024 * 1024; // 5MB
  let downloadedBytes = 0;
  
  // 获取文件总大小
  const response = await fetch(`/api/files/${fileId}/size`);
  const totalSize = parseInt(await response.text());
  
  // 检查本地是否有已下载部分
  const tempFile = await checkLocalProgress(fileName);
  if (tempFile) {
    downloadedBytes = tempFile.size;
  }
  
  // 分片下载
  while (downloadedBytes < totalSize) {
    const end = Math.min(downloadedBytes + CHUNK_SIZE - 1, totalSize - 1);
    const response = await fetch(`/api/files/${fileId}/download`, {
      headers: { Range: `bytes=${downloadedBytes}-${end}` }
    });
    
    if (!response.ok) throw new Error("下载失败");
    
    const blob = await response.blob();
    await appendToFile(tempFile, blob);
    downloadedBytes += blob.size;
    
    // 更新进度
    updateProgress(downloadedBytes / totalSize);
  }
  
  // 完成后重命名文件
  await renameTempFile(tempFile, fileName);
}

// 检查本地进度
async function checkLocalProgress(fileName) {
  const tempPath = `/temp/${fileName}.part`;
  return new Promise(resolve => {
    fs.stat(tempPath, (err, stats) => {
      if (err) resolve(null);
      else resolve(fs.createWriteStream(tempPath, { flags: 'a' }));
    });
  });
}

​​四、关键优化点​​

​内存管理​

使用InputStream流式传输,避免大文件加载到内存。

​并发控制​

通过线程池限制同时下载的分片数:

@Service
public class DownloadService {
    private final ExecutorService executor = Executors.newFixedThreadPool(10);
    
    public void downloadChunk(String fileId, long start, long end) {
        executor.submit(() -> {
            // 分片下载逻辑
        });
    }
}

​进度存储​

使用Redis记录每个文件的下载进度:

@Autowired
private RedisTemplate<String, String> redisTemplate;

public void saveProgress(String fileId, long downloadedBytes) {
    redisTemplate.opsForValue().set(fileId, String.valueOf(downloadedBytes));
}

​​五、测试方案​​

​正常下载​

curl -H "Range: bytes=0-999" http://localhost:8080/download

​断点续传​

中断后重新发起相同请求,验证是否从断点续传。

​多线程下载​

使用工具(如Postman)模拟多线程分片请求。

​​六、扩展场景​​

  • ​视频流播放​​:通过Content-Range实现视频边下边播。
  • ​大文件秒传​​:基于文件MD5校验,避免重复传输。
  • ​分布式存储​​:结合MinIO/S3实现分片存储与合并。

通过上述方案,可高效实现大文件的分片下载和断点续传,支持弱网环境和超大文件传输。完整代码示例可参考GitHub仓库(需替换实际存储路径)。

到此这篇关于SpringBoot中实现大文件分片下载和断点续传功能的完整指南的文章就介绍到这了,更多相关SpringBoot大文件分片下载和断点续传内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持

相关文章

  • mybatis深入讲解resultMap的定义及用法

    mybatis深入讲解resultMap的定义及用法

    MyBatis的每一个查询映射的返回类型都是ResultMap,当我们提供返回类型属性是resultType时,MyBatis会自动给我们把对应值赋给resultType所指定对象的属性,当我们提供返回类型是resultMap时,将数据库中列数据复制到对象的相应属性上,可以用于复制查询,两者不能同时用
    2022-04-04
  • SpringBoot中ClientAbortException: Broken pipe异常解决及优化方案

    SpringBoot中ClientAbortException: Broken pipe异常解决及优

    这篇文章主要介绍了如何解决 Spring Boot 中的 ClientAbortException: Broken pipe 异常及优化方案,异常发生在 Spring Boot 项目中,表示客户端与服务端的 HTTP 请求连接被中断,接下来由小编给大家介绍一下出现这个问题的原因,需要的朋友可以参考下
    2024-12-12
  • Java程序单实例运行的简单实现

    Java程序单实例运行的简单实现

    这篇文章主要介绍了Java程序单实例运行的简单实现方式,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2021-08-08
  • Struts2拦截器登录验证实例

    Struts2拦截器登录验证实例

    本篇文章主要介绍了Struts2拦截器登录验证实例,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2017-05-05
  • Spring-Security实现登录接口流程

    Spring-Security实现登录接口流程

    Security 是 Spring 家族中的一个安全管理框架,SpringSecurity的原理其实就是一个过滤器链,内部包含了提供各种功能的过滤器,这篇文章主要介绍了Spring-Security实现登录接口,需要的朋友可以参考下
    2023-05-05
  • Java判断一个实体是不是空的简单方法

    Java判断一个实体是不是空的简单方法

    这篇文章主要给大家介绍了关于Java判断一个实体是不是空的简单方法,实际项目中我们会有很多地方需要判空校验,文中给出了详细的示例代码,需要的朋友可以参考下
    2023-07-07
  • IDEA上面搭建一个SpringBoot的web-mvc项目遇到的问题

    IDEA上面搭建一个SpringBoot的web-mvc项目遇到的问题

    这篇文章主要介绍了IDEA上面搭建一个SpringBoot的web-mvc项目遇到的问题小结,需要的朋友可以参考下
    2017-04-04
  • 关于spring中定时器的使用教程

    关于spring中定时器的使用教程

    大家应该都有所体会,在很多实际的web应用中,都有需要定时实现的服务,下面这篇文章主要给大家介绍了关于spring中定时器的使用教程,对大家具有一定的参考学习价值,需要的朋友们下面来一起看看吧。
    2017-06-06
  • Java中eq、ne、ge、gt、le、lt的含义详细解释

    Java中eq、ne、ge、gt、le、lt的含义详细解释

    Java中的比较运算符包括eq(等于)、ne(不等于)、ge(大于或等于)、gt(大于)、le(小于或等于)和lt(小于),这些运算符在控制流语句和条件语句中用于判断条件是否满足,从而决定程序的执行路径,需要的朋友可以参考下
    2024-11-11
  • 深入理解Spring Boot Starter概念、特点、场景、原理及自定义starter的方法

    深入理解Spring Boot Starter概念、特点、场景、原理及自定义starter的方法

    本文将深入探讨Spring Boot Starter的基本概念、主要特点、应用场景以及实现原理,帮助读者更好地理解和应用这一强大工具,感兴趣的朋友跟随小编一起看看吧
    2025-08-08

最新评论