H5 大文件分片上传设计
H5 大文件分片上传设计
大文件一次性上传容易受弱网、页面切换和服务超时影响。分片上传把文件切成小块,允许有限并发、失败重试和断点续传。但它需要服务端共同定义文件标识、分片校验、合并顺序和过期清理,不能只由前端切割文件就保证可靠。
一、选择文件并尽早校验
<label for="file-input">选择文件</label>
<input id="file-input" type="file">
选择后先检查业务允许的大小、类型和数量。前端校验用于及时反馈,服务端仍必须独立校验,不能信任浏览器提供的文件名和类型。
二、按固定大小切片
type FileChunk = {
index: number;
start: number;
end: number;
blob: Blob;
};
function splitFile(file: File, chunkSize: number): FileChunk[] {
const chunks: FileChunk[] = [];
for (let start = 0, index = 0; start < file.size; start += chunkSize, index += 1) {
const end = Math.min(start + chunkSize, file.size);
chunks.push({
index,
start,
end,
blob: file.slice(start, end)
});
}
return chunks;
}
分片过小会增加请求数量,过大则失败重传成本高。大小应根据网络、服务限制和设备内存测量。
三、建立稳定上传会话
开始上传时,客户端向服务端提交文件元数据,获得稳定会话标识。后续每个分片携带:
- 上传会话标识。
- 分片序号和总数。
- 当前分片大小。
- 文件整体或分片校验值。
服务端使用会话隔离不同文件,并拒绝不符合约定的序号和大小。
四、控制并发数量
同时上传所有分片会占满网络和内存。可以使用固定工作池:
async function uploadWithConcurrency(
chunks: readonly FileChunk[],
concurrency: number,
upload: (chunk: FileChunk) => Promise<void>
): Promise<void> {
if (!Number.isInteger(concurrency) || concurrency <= 0) {
throw new Error('并发数量必须为正整数');
}
let nextIndex = 0;
async function worker(): Promise<void> {
while (nextIndex < chunks.length) {
const chunk = chunks[nextIndex];
nextIndex += 1;
await upload(chunk);
}
}
const workers = Array.from(
{ length: Math.min(concurrency, chunks.length) },
() => worker()
);
await Promise.all(workers);
}
并发参数必须大于零,并根据移动网络表现设定合理上限。
五、进度按字节计算
分片完成数量不能准确代表进度,因为最后一片大小可能不同,进行中的分片也已有传输量。
function calculateProgress(
uploadedBytes: number,
totalBytes: number
): number {
if (totalBytes === 0) return 1;
return Math.min(1, uploadedBytes / totalBytes);
}
多个并发分片的已传字节需要按分片分别记录,不能把重复进度事件累加两次。
六、只重试合适错误
短暂断网和服务繁忙可以按有限次数重试;文件不合法、会话过期和权限拒绝重复上传也不会成功。
重试应带退避间隔,并支持用户取消。分片操作要幂等,相同会话和序号重复到达时不能写入两份数据。
七、断点续传查询服务端状态
页面恢复后,不能只相信本地记录哪些分片成功。应查询服务端已确认分片集合,再上传缺失部分。
浏览器出于安全原因不会在重新打开页面后自动恢复文件对象,通常仍需要用户重新选择同一文件,并通过大小、名称和内容校验确认一致。
本地只保存非敏感会话元数据,并设置过期清理。
八、完成合并要独立确认
所有分片上传成功后,客户端发起完成命令。服务端校验总数、顺序和整体内容后合并,并返回最终文件标识。
前端只有收到完成确认后才能显示上传成功。分片全部传输结束不等于服务端已经生成可用文件。
九、取消与清理
用户取消时应停止在途请求,并通知服务端废弃会话。服务端还需要定期清理长时间未完成的临时分片。
组件销毁是否取消上传由产品决定。需要跨页面继续时,应把任务提升到应用级管理器,并保留可观察进度,而不是让页面对象长期存活。
十、安全检查
服务端必须验证文件内容、大小、分片数量和最终用途。文件名不能直接作为存储位置,预览与下载时也要设置正确内容处理策略。
日志只记录会话标识、分片序号和错误阶段,不输出用户文件内容。
总结
分片上传是前后端共同协议。固定边界切片,控制并发,按字节汇总进度,以幂等分片支持有限重试,再由服务端确认断点和最终合并。取消、过期和临时数据清理同样属于完整上传生命周期。
- 点赞
- 收藏
- 关注作者
评论(0)