日常开发中使用 javascript 实现文件上传非常简单,但是在上传大文件时,由于连接不稳定,上传可能会中途失败,导致整个过程需要重新开始,从而造成时间和带宽的浪费,导致用户流失。

解决这个问题的实用方法是实施文件切片/分块,即将大文件分成较小的部分,然后一次上传一个,全部上传完成后,在服务端合并文件即可。这样遇到错误时,只是当前切片/分块上传失败,重新尝试上传该切片/分块即可,而不需要全部重新开始。本文就分享一下在客户端用 JavaScript 实现大文件切片/分块上传的方法。

JavaScript 实现文件切片/分块

在 JavaScript 中,Blob对象的slice方法允许我们实现文件切片/分块。slice方法可用于创建一个新Blob(片),其中包含指定起点和终点的原始Blob中的数据。

假设我们要上传一个视频文件。基本过程如下:

  1. 通过 HTML input 元素选择文件。
  2. 使用 JavaScript 将文件分割成块。
  3. 逐块发送到服务器。

示例代码:

// HTML input 输入框
<input type="file" id="file-upload">

// JavaScript 文件处理
const fileInput = document.getElementById('file-upload');
fileInput.addEventListener('change', handleFileUpload);

function handleFileUpload(event) {
  const file = event.target.files[0];
  const chunkSize = 1024 * 1024; // 每块大小 (1MB)
  let start = 0;

  while (start < file.size) {
    uploadChunk(file.slice(start, start + chunkSize));
    start += chunkSize;
  }
}

function uploadChunk(chunk) {
  const formData = new FormData();
  formData.append('file', chunk);

  // Make a request to the server
  fetch('/upload-endpoint', {
    method: 'POST',
    body: formData,
  });
}

在上面的示例中,我们首先使用 HTML input 元素选择文件。然后,我们为输入元素添加一个事件监听器,每当有文件被选中,该监听器就会触发handleFileUpload函数。该函数会将所选文件切成若干块,并调用uploadChunk函数将每一块上传到服务器。

错误处理和重试机制

在网络连接不稳定的情况下,即便分块很小,但上传请求仍然有可能会失败。因此,我们需要一种机制来处理这些失败。我们可以完善一下uploadChunk函数,在请求最终失败前重试一定次数:

async function uploadChunk(chunk, retries = 3) {
  const formData = new FormData();
  formData.append('file', chunk);

  try {
    await fetch('/upload-endpoint', {
      method: 'POST',
      body: formData,
    });
  } catch (error) {
    if (retries > 0) {
      await uploadChunk(chunk, retries - 1);
    } else {
      console.error('码农资源网[www.codesou.cn]提示:分块上传失败: ', error);
    }
  }
}

完善后的uploadChunk 函数使用 try-catch 块来封装获取请求。如果请求失败,我们会捕获错误并重试请求。我们会跟踪重试次数,只有在指定的重试次数用完后才会失败。

到此,一个简单的 javascript 文件切片/分块上传功能就实现完成了,接下来在服务端接收请求、合并保存文件即可。也可参考本站的 PHP 实现文件分块上传教程一文。