大文件上传到一半断网,怎样接着传
上传一个几千兆字节的视频,进度走到百分之九十时网络断开。如果页面只能让用户重新开始,之前消耗的时间和带宽几乎都白费了。分片上传的价值,就是把一次很大的传输拆成多个可以独立确认的小任务。
不过,把文件切成几块并行发送,还不能算完整的断点续传。服务器需要知道这些分片属于哪次上传、哪些已经可靠保存,以及什么时候可以把它们视为一个完整文件。
通常先由客户端向服务器申请上传会话。服务器返回不可预测的 uploadId,并约定分片大小、有效期和大小限制。客户端随后按固定规则切片:
function getChunk(file, index, chunkSize) {
const start = index * chunkSize;
return file.slice(start, Math.min(start + chunkSize, file.size));
}
const chunkSize = 8 * 1024 * 1024;
const totalChunks = Math.ceil(file.size / chunkSize);
for (let index = 0; index < totalChunks; index++) {
const chunk = getChunk(file, index, chunkSize);
// 将 uploadId、index 和 chunk 发送给服务端,并等待保存确认。
}
这段代码只展示切片规则,不包含上传会话、重试和鉴权。服务端需要采用相同的编号约定,并根据会话里记录的文件大小、分片大小计算预期片数。空文件也要单独约定,避免计算得到零片后进入永远无法完成的等待状态。
每个分片上传成功后,服务器记录已接收的编号。客户端恢复任务时,先查询已保存的分片列表,只补传缺失部分。因此进度条更适合基于“服务器已经确认保存的字节数”计算,而不是仅根据客户端已经读出多少数据判断完成。
响应丢失也必须考虑:服务器可能已经存好分片,客户端却以为失败。相同会话里的同一编号再次到达时,服务端应识别重复传输;如果内容不一致,应明确拒绝或按事先定义的规则重新校验,不能悄悄混用两份文件。
恢复上传还有一个难点:页面重新打开后,用户选中的文件是否真的是原文件。文件名、大小和最后修改时间可以帮助快速匹配,但不能证明内容完全相同。需要更严格识别时,可以计算内容摘要,或结合分片摘要校验。对大文件,直接一次性读取全部内容会增加内存压力,应使用支持增量处理的方案,必要时放到 Worker 中执行。
无论采用什么摘要,文件指纹都不能作为访问权限。服务器仍需检查当前用户是否有权操作这个 uploadId,并限制分片数量、单片大小、总容量和会话生命周期。相同文件可能属于不同用户,不能仅凭摘要就把他人的私有文件交出去。
客户端通常不需要同时发送几十个分片。过高并发可能争抢连接、占满带宽,也会放大服务端内存和临时存储压力。可以从少量并发开始,根据网络和服务端限制调整。暂停时取消正在进行的请求,但取消客户端请求不代表服务端一定停止保存,恢复前仍然要重新查询状态。
全部分片到齐后,还需要一个完成步骤。服务器核对编号、预期大小和必要的校验信息,按顺序合并或完成对象存储中的分片任务,最后把会话标记为可用。这个标记应在结果可靠就绪后更新,避免页面拿到地址却读到半成品。对废弃会话还要设置清理策略,防止临时数据无限积累。
验证时,可以在传输中主动断网、关闭页面,再重新选择同一文件,观察是否只补传缺失部分。还应测试重复分片、错误编号、不同文件误用会话,以及最后一步响应丢失后的状态查询。断点续传真正解决的是中断之后怎样确认进度,而不仅是把一个大文件切成若干个小文件。
- 点赞
- 收藏
- 关注作者
评论(0)