大文件切片上传场景
大文件切片上传是处理大文件(视频、镜像、数据集等)的标准方案。核心思路:前端将大文件切分为多个小片段(Chunk),逐片上传到后端,后端存储到MinIO/OSS,全部上传完成后合并为一个完整文件。配合MD5校验实现秒传和断点续传。
一、核心流程总览
三大核心流程:秒传(MD5去重)→ 分片上传(并发上传到MinIO)→ 合并文件(前端触发合并请求)。断点续传作为增强功能贯穿其中。
1.1 整体架构图
二、核心流程详解
2.1 流程一:秒传(MD5去重检测)
原理:文件MD5值是其内容的唯一指纹。如果服务端已存储过相同MD5的文件,直接返回文件URL,跳过上传过程,实现"秒传"。
接口设计
|
场景 |
处理 |
|---|---|
|
MD5已存在且文件完整 |
秒传,直接返回已有文件URL,跳过上传 |
|
MD5已存在但文件不完整 |
返回已上传的分片索引列表(断点续传) |
|
MD5不存在 |
全新上传,前端开始分片上传 |
2.2 流程二:分片上传
前端:使用 File.slice() 将文件切分,通过 Web Worker 计算MD5,并发上传分片。后端:接收每个分片,直接写入MinIO的临时目录,Redis记录分片上传状态。
前端核心代码
后端分片上传接口
分片元数据设计
并发控制要点
- 前端并发数:控制在3-5个(浏览器有同域并发连接限制,Chrome默认6个)
- 分片大小:建议5MB-10MB每片(MinIO单次PUT上限5TB)
- 失败重试:单分片失败自动重试3次,指数退避
- 进度上报:(已上传分片数 / 总分片数) × 100%
2.3 流程三:合并文件
所有分片上传完成后,前端请求合并接口。后端调用MinIO的composeObject API,将多个分片对象按顺序合并为一个完整的文件对象。MinIO的compose操作是服务端操作,不经过后端服务器,不消耗带宽。
MinIO compose限制:单次compose最多合并1000个源对象。如果超过1000个分片,需要分批compose:先每1000个合并为中间对象,再合并中间对象为最终文件。
三、断点续传
断点续传的核心:前端在秒传检查阶段获取已上传的分片列表 → 跳过已上传的分片 → 只上传缺失的分片 → 全部完成后同样请求合并。
3.1 实现方案
|
方案 |
实现 |
|---|---|
|
Redis存储(推荐) |
Key: upload:chunks:{fileMd5} Value: Set<Integer>(已上传的chunkIndex集合)。设置过期时间(24h),过期后未合并则需重新上传 |
|
MinIO本身 |
每次上传前通过 minioClient.statObject() 检查分片是否已存在于MinIO,存在则跳过 |
|
前端localStorage |
前端本地记录已上传分片列表,刷新页面也能恢复(辅助方案) |
3.2 断点续传check接口增强
四、完整数据库设计
|
字段 |
类型 |
说明 |
|---|---|---|
|
id |
bigint |
主键 |
|
file_md5 |
varchar(64) |
文件MD5值(唯一索引) |
|
file_name |
varchar(255) |
原始文件名 |
|
file_size |
bigint |
文件大小(字节) |
|
storage_path |
varchar(500) |
MinIO中的对象路径 |
|
total_chunks |
int |
总分片数 |
|
chunk_size |
bigint |
单片大小(字节) |
|
status |
tinyint |
0=UPLOADING / 1=COMPLETED / 2=MERGING / 3=FAILED |
|
create_time |
datetime |
创建时间 |
|
update_time |
datetime |
更新时间 |
五、边界与异常处理
|
场景 |
处理方案 |
|---|---|
|
单个分片上传失败 |
前端自动重试3次,指数退避(1s→2s→4s),仍失败则上报用户 |
|
网络中断恢复 |
断点续传:重新调用check接口获取已上传分片,跳过已上传的 |
|
浏览器关闭后重开 |
localStorage存(fileMd5 + totalChunks),刷新后恢复上传状态 |
|
并发上传同一文件 |
秒传检查阶段发现文件已COMPLETED,直接返回URL(乐观锁) |
|
分片超1000个 |
分批compose合并(每1000片合并为中间对象,最终再合并中间对象) |
|
合并过程中断 |
合并前设置status=MERGING,合并成功后设为COMPLETED。定时任务清理超时MERGING状态并重试 |
|
Redis分片记录过期 |
Redis key设置TTL=24h。过期后重新查询MinIO已有分片重建记录 |
|
文件为空 |
前端上传前检查file.size > 0;后端拒绝size=0的分片 |
六、你项目中的集成方案
这个方案可以完整集成到你的Spring Boot项目中:
- 新增依赖:minio(S3 SDK)+ spring-boot-starter-data-redis + SparkMD5(前端)
- 新增接口:/upload/check、/upload/chunk、/upload/merge 三个接口
- 新增表:t_file_info(文件记录表,字段如上表)
- 配置MinIO:application.yml中配置minio.endpoint/accessKey/secretKey/bucket
- 前端改造:引入SparkMD5计算文件MD5 + File.slice()切片 + 并发上传逻辑
- Redis:使用SET存储已上传分片索引,TTL=24h
效果总结:
- 秒传:相同文件(同MD5)跳过上传,直接复用,节省带宽和时间
- 切片上传:大文件分片并发上传,速度提升3-5倍
- 断点续传:网络中断后只上传未完成的分片,不从头开始
- MinIO compose:合并操作在服务端完成,不消耗后端带宽
- MD5校验:文件级MD5防重复,分片级MD5防传输错误