需求是上传几百 MB 到几个 GB 的视频文件,直接 FormData 丢上去肯定不行:超时、断网重来、服务器内存爆。分片是必须的。
整体流程
- 前端计算文件 hash(可以用 spark-md5 增量计算)
- 把 hash 发给后端,问「这个文件传过没」——传过直接秒传
- 没传过,问「哪些分片已经传了」——返回已传分片索引
- 前端只传缺失的分片
- 全传完通知后端合并
关键点:hash 计算别阻塞 UI
大文件算 MD5 很慢,放主线程会卡死。用 Web Worker,或者用 requestIdleCallback 分片算。spark-md5 支持增量计算,配合 FileReader 的 slice 读。
const chunkSize = 2 * 1024 * 1024; // 2MB
const chunks = Math.ceil(file.size / chunkSize);
const spark = new SparkMD5.ArrayBuffer();
const reader = new FileReader();
function loadNext(i) {
if (i >= chunks) {
const hash = spark.end();
checkFile(hash);
return;
}
const blob = file.slice(i * chunkSize, (i + 1) * chunkSize);
reader.readAsArrayBuffer(blob);
}
reader.onload = e => {
spark.append(e.target.result);
loadNext(currentIndex++);
};
并发控制
别一次性发几百个请求,浏览器会崩。控制在 3~6 个并发,用 Promise 池或者 p-limit。
断点续传
刷新页面后,重新算 hash(或者把 hash 存 localStorage),再问一次后端已传分片,接着传。后端每个分片单独存临时文件,合并时按顺序拼。
踩过的坑
- 分片太小请求太多,太大单请求超时,2~5MB 比较合适
- 合并时后端要校验总分片数和文件大小
- 临时分片要设过期清理,不然磁盘会被撑爆
- 秒传要防伪造,hash 不能完全信前端

Comments 3 条评论
spark-md5 算大文件是真卡
秒传不校验 hash 容易被刷
我们分片一直用 2M,再大就超时