1. 大文件分片上传的核心挑战与解决方案
在Web应用开发中,文件上传是一个基础但至关重要的功能。当面对几百MB甚至几十GB的大文件时,传统的直接上传方式会暴露出诸多问题:
传统上传方式的痛点:
- 超时风险:HTTP请求长时间未完成会被服务器或浏览器中断
- 内存溢出:服务端需要将整个文件加载到内存中处理
- 网络波动:一旦中断需要重新上传整个文件
- 进度反馈:无法提供精确的上传进度显示
分片上传的四大优势:
- 可靠性提升:单个分片失败只需重传该分片
- 内存友好:每次只处理小分片数据
- 进度可控:可以精确计算和显示上传百分比
- 并发加速:可以并行上传多个分片
我们的生产级解决方案采用"前端分片+后端随机写入"的架构,主要包含以下技术组件:
- 前端使用SparkMD5计算文件指纹
- 基于RandomAccessFile的直接偏移写入
- 使用.conf文件记录分片状态
- Redis缓存秒传状态
- 支持并行上传和乱序接收
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 系统架构设计与核心流程
2.1 整体架构图
code复制[前端] → [分片上传] → [Spring Boot后端] → [临时文件存储]
↑ ↓ ↗
[MD5计算] [状态检查接口] [最终文件存储]
↓ ↖ ↓
[Redis缓存] ← [状态更新] [数据库记录]
2.2 核心上传流程
-
预处理阶段:
- 前端计算文件MD5(使用SparkMD5)
- 调用/check接口检查文件状态
- 根据返回结果决定是否秒传或断点续传
-
分片上传阶段:
- 将文件按固定大小(如5MB)分片
- 并发上传各分片到/uploadChunk接口
- 后端将分片写入临时文件的指定位置
-
完成阶段:
- 所有分片上传完成后调用/merge接口
- 后端重命名临时文件为最终文件
- 更新Redis和数据库记录
2.3 关键数据结构设计
分片上传请求体(ChunkUploadRequest):
java复制@Data
public class ChunkUploadRequest {
private String md5; // 文件整体MD5
private Integer chunkIndex; // 当前分片序号(0-based)
private Integer totalChunks; // 总分片数
private Long chunkSize; // 分片大小(字节)
private String fileName; // 原始文件名
private MultipartFile file; // 当前分片文件流
}
状态检查响应体(CheckResult):
java复制@Data
@AllArgsConstructor
public class CheckResult {
private boolean uploaded; // 是否已秒传
private List<Integer> uploadedChunks; // 已上传分片列表
private String url; // 已存在时的文件URL
}
3. 后端核心实现详解
3.1 配置文件解析
application.yml关键配置:
yaml复制upload:
chunk-size: 5 # 分片大小(MB)
temp-dir: /data/upload/temp/ # 临时目录
final-dir: /data/upload/files/ # 正式目录
spring:
servlet:
multipart:
enabled: true
max-file-size: -1 # 单个分片无限制
max-request-size: -1
生产建议:
- 临时目录和正式目录最好放在不同磁盘
- 对于超大型文件(10GB+),分片大小可适当增大到10-20MB
- 确保目录有足够的写入权限
3.2 状态检查接口实现
java复制public CheckResult checkFile(String md5, Integer totalChunks) {
// 1. 秒传判断
String status = redisTemplate.opsForValue()
