大文件断点续传实现

通过分片上传和断点续传技术实现大文件上传

问题

如何实现大文件的断点续传?上传大文件时会遇到服务器处理能力限制、请求超时、网络波动等问题,导致上传时间长、失败率高,失败后需要重新上传。

解答

分片上传

将文件按照固定大小分割成多个数据块,分别上传后由服务端合并成原始文件。

流程:

  1. 将文件按规则分割成相同大小的数据块
  2. 初始化分片上传任务,获取唯一标识
  3. 按策略(串行或并行)发送各个分片
  4. 服务端验证数据完整性后合并文件

断点续传

将上传任务划分为多个部分,网络故障时可以从已完成部分继续上传,无需从头开始。

实现方式:

服务器端将文件写为临时文件,记录已上传大小。中断后,下次上传时根据临时文件大小作为偏移量,从该位置继续读取和写入文件。

代码实现

读取文件

const input = document.querySelector('input');
input.addEventListener('change', function() {
    const file = this.files[0];
});

生成文件唯一标识

const md5code = md5(file);

分割文件

const chunkSize = 2 * 1024 * 1024; // 2MB
const chunks = Math.ceil(file.size / chunkSize);

for (let i = 0; i < chunks; i++) {
    const start = i * chunkSize;
    const end = Math.min(start + chunkSize, file.size);
    const chunk = file.slice(start, end);
    
    // 上传分片
    uploadChunk(chunk, i, md5code);
}

上传分片

function uploadChunk(chunk, index, fileHash) {
    const formData = new FormData();
    formData.append('chunk', chunk);
    formData.append('index', index);
    formData.append('hash', fileHash);
    
    fetch('/upload', {
        method: 'POST',
        body: formData
    });
}

服务端合并文件

// 所有分片上传完成后
function mergeChunks(fileHash, totalChunks) {
    fetch('/merge', {
        method: 'POST',
        body: JSON.stringify({ hash: fileHash, total: totalChunks })
    });
}

关键点

  • 使用文件哈希(如 MD5)作为唯一标识,用于断点续传时识别文件
  • 将大文件切割成固定大小的分片(如 2MB),降低单次请求压力
  • 服务端保存临时文件和上传进度,支持从中断位置继续上传
  • 可采用并行上传提高速度,需控制并发数避免浏览器限制
  • 所有分片上传完成后,服务端按顺序合并为完整文件