SpringBoot中实现大文件分片下载和断点续传功能的完整指南
目录
- 一、核心原理
- 二、服务端实现
- 1. 分片下载接口
- 2. 断点续传支持
- 三、客户端实现(JavaScript示例)
- 四、关键优化点
- 五、测试方案
- 六、扩展场景
在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 headerpythons = new HttpHeaders(); headers.setContentType(MediaType.APPLICATION_OCTET_STREAM); headers.setContentLength(end - start + 1); headers.setHeadepythonr("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(djavascriptownloadedBytes + 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, lhttp://www.devze.comong 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大文件分片下载和断点续传内容请搜索编程客栈(www.devze.com)以前的文章或继续浏览下面的相关文章希望大家以后多多支持
精彩评论