大文件分片上传

335 阅读2分钟

序言

文件上传是我们经常遇到的一个业务。一般就是用户点击上传,我们拿到 File 数据,再传给后端。但当文件体积过大,‌一次性上传可能会导致传输时间过长,‌且在网络不稳定的情况下容易失败,‌需要重新上传整个文件,‌这不仅浪费资源,‌还大大降低了用户体验。‌因此,‌分片上传技术应运而生,‌通过将大文件分割成多个小片(‌Part)‌,‌每个小片可以独立地上传,‌并在服务器端重新组合成完整的文件。话不多说,我们进入正题。

分片

分片,顾名思义就是将文件进行拆分成多个块 chunk。分片规则可以根据业务所决定,以下我们假设,每个 chunk 的最大为 10M,那么分片的代码如下。


const chunkSize = 10 * 1024 * 1024;
const chunkCount = Math.ceil(file.size / chunkSize); // 总片数

for (let chunkIndex = 0; chunkIndex < chunkCount; chunkIndex++) {
    const start = chunkIndex * chunkSize;
    const end = Math.min(file.size, start + chunkSize);
    const chunk = file.slice(start, end);
    
    // 此时 chunk 就是我们所分片出来的数据
}

上传

一般呢。我们拿到分片数据 chunk 后,就可以上传给后端。但后端还需要校验最后上传到后端的文件的完整性。一般是采用 md5 进行加密后验证。

import SparkMD5 from 'spark-md5';

function readAsArrayBuffer(blob: Blob) {
  return new Promise<ArrayBuffer>((resolve, reject) => {
    const reader = new FileReader();

    reader.onload = function (event) {
      resolve(event.target.result as ArrayBuffer);
    };

    reader.onerror = (error) => {
      reject(error);
    };

    reader.readAsArrayBuffer(blob);
  });
};

function fileSliceUpload() {
    const chunkSize = 10 * 1024 * 1024;
    const chunkCount = Math.ceil(file.size / chunkSize); // 总片数
    
    const md5 = new SparkMD5.ArrayBuffer();

    for (let chunkIndex = 0; chunkIndex < chunkCount; chunkIndex++) {
        const start = chunkIndex * chunkSize;
        const end = Math.min(file.size, start + chunkSize);
        const chunk = file.slice(start, end);

        // 计算md5
        const chunkBuffer = await readAsArrayBuffer(chunk);
        md5.append(chunkBuffer);
    
        // 此时 chunk 就是我们所分片出来的数据
        // 进行 partUpload
    }
    
    // 上传完毕
    // uploadComplete(md5.end());
    // 校验上传文件的完整性
}

结尾

以上就是分片上传的大致思路啦。欢迎大家讨论交流