大文件切片上传和断点续传

大文件切片上传和断点续传

一、技术原理

  1. 文件切片上传

    • 将大文件按固定大小(如5MB)分割为多个切片(Blob对象的slice()方法实现)。
    • 通过文件内容的哈希值(如MD5)生成唯一标识,用于服务端校验文件完整性。
    • 切片上传支持并行传输和失败重试,减少单次请求压力。
  2. 断点续传

    • 客户端记录已上传的切片索引(如通过localStorage),上传前与服务端校验未上传的切片。
    • 服务端需保存切片的上传状态(如Redis记录哈希值或文件分片状态)。

二、前端实现步骤

1. 文件切片与哈希计算
// 切片函数(以50KB为例)
function splitFile(file, chunkSize = 1024 * 50) {
  const chunks = [];
  let cur = 0;
  while (cur < file.size) {
    chunks.push(file.slice(cur, cur + chunkSize));
    cur += chunkSize;
  }
  return chunks;
}

// 计算文件哈希(使用SparkMD5)
async function calculateHash(chunks) {
  const spark = new SparkMD5.ArrayBuffer();
  for (const chunk of chunks) {
    const buffer = await chunk.arrayBuffer();
    spark.append(buffer);
  }
  return spark.end(); // 生成唯一哈希值
}

优化:使用Web Worker避免哈希计算阻塞主线程。

2. 断点续传逻辑
// 检查已上传切片(示例为React)
const checkUploadedChunks = async (fileName, totalChunks) => {
  const res = await axios.get('/check-upload', { params: { fileName } });
  return res.data.uploadedIndexes; // 服务端返回已上传的切片索引
};

// 上传逻辑(支持续传)
const uploadFile = async (file) => {
  const chunks = splitFile(file);
  const hash = await calculateHash(chunks);
  const uploaded = await checkUploadedChunks(hash);
  
  for (let i = 0; i < chunks.length; i++) {
    if (uploaded.includes(i)) continue; // 跳过已上传的切片
    
    const formData = new FormData();
    formData.append('file', chunks[i]);
    formData.append('hash', hash);
    formData.append('index', i);
    
    await axios.post('/upload', formData);
    localStorage.setItem(hash, JSON.stringify([...uploaded, i])); // 记录进度
  }
  
  await axios.post('/merge', { hash }); // 通知服务端合并切片
};

三、后端处理要点

  1. 切片接收与存储

    • 使用Node.js的multer中间件接收切片,按哈希值分目录存储。
    • 示例代码:
    app.post('/upload', upload.single('file'), (req, res) => {
      const { hash, index } = req.body;
      const chunkPath = `./uploads/${hash}/${index}`;
      fs.writeFileSync(chunkPath, req.file.buffer); // 保存切片
      res.send({ success: true });
    });
    
  2. 合并切片

    • 按索引顺序读取切片文件,合并为完整文件:
    app.post('/merge', (req, res) => {
      const { hash } = req.body;
      const chunks = fs.readdirSync(`./uploads/${hash}`);
      chunks.sort((a, b) => a - b);
      const mergedFile = chunks.map(chunk => 
        fs.readFileSync(`./uploads/${hash}/${chunk}`)
      );
      fs.writeFileSync(`./uploads/${hash}.mp4`, Buffer.concat(mergedFile));
      res.send({ success: true });
    });
    

四、优化策略

  1. 秒传
    • 服务端在接收哈希值后,若文件已存在,直接返回成功。
  2. 并行上传
    • 使用Promise.all同时上传多个切片(需控制并发数)。
  3. 进度显示
    • 通过已上传切片数与总数计算进度百分比,更新UI。
  4. 错误重试
    • 为每个切片设置重试机制(如3次重试上限)。

总结

通过切片上传和断点续传技术,可显著提升大文件上传的稳定性及用户体验。关键点包括文件哈希生成、分片状态管理、服务端合并逻辑及错误处理。实际开发中需根据场景优化参数(如切片大小、并发数)。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值