你知道断点续传的原理吗?用js怎么实现?

我知道断点续传的原理。它主要依靠 HTTP 协议中的一些特性来实现。核心思想是将一个大文件分成多个小块,客户端每次只请求一部分数据,并在服务器端记录已下载的部分。如果下载中断,客户端可以根据已下载的记录,从中断的地方继续下载,避免重复下载已完成的部分。

以下是断点续传的原理和用 JavaScript 实现的方法:

原理:

  1. 分块请求: 客户端将文件分成多个小块,并记录每个块的大小和起始位置。

  2. Range 请求头: 客户端使用 HTTP 请求头 Range 指定要下载的字节范围。例如,Range: bytes=0-999 表示请求文件的第一个 1000 字节。

  3. 服务器响应: 服务器收到带有 Range 请求头的请求后,会返回状态码 206 Partial Content 和请求的字节范围,并在响应头 Content-Range 中指明返回数据的范围和文件总大小。

  4. 客户端记录: 客户端收到响应后,将下载的数据块写入本地文件,并记录已下载的字节范围。

  5. 断点续传: 如果下载中断,客户端重新发送请求,并在 Range 请求头中指定上次下载中断的位置。

JavaScript 实现 (前端):

async function downloadFile(url, fileName) {
  const fileSize = await getFileSize(url); // 获取文件大小
  const chunkSize = 1024 * 1024 * 4; // 4MB 每块大小
  let downloaded = 0;

  try {
    const fileHandle = await window.showSaveFilePicker({
      suggestedName: fileName,
      types: [{
        description: 'All Files',
        accept: {'*/*': ['.']},
      }],
    });
    const writable = await fileHandle.createWritable();

    while (downloaded < fileSize) {
      const start = downloaded;
      const end = Math.min(downloaded + chunkSize - 1, fileSize - 1);

      const response = await fetch(url, {
        headers: {
          'Range': `bytes=${start}-${end}`
        }
      });

      if (!response.ok) {
        throw new Error(`HTTP error ${response.status}`);
      }

      const reader = response.body.getReader();
      while (true) {
        const { done, value } = await reader.read();
        if (done) {
          break;
        }
        await writable.write(value);
        downloaded += value.length;
        // 可以在这里更新下载进度
        console.log(`Downloaded ${downloaded} of ${fileSize} bytes.`);
      }
    }

    await writable.close();
    console.log('Download complete!');

  } catch (error) {
    console.error('Download failed:', error);
  }
}

async function getFileSize(url) {
  const response = await fetch(url, { method: 'HEAD' });
  if (!response.ok) {
    throw new Error(`HTTP error ${response.status}`);
  }
  return parseInt(response.headers.get('Content-Length'));
}


// 使用示例:
downloadFile('https://example.com/large_file.zip', 'large_file.zip');

关键点:

  • showSaveFilePicker API: 用于创建或选择一个文件,以便写入下载的数据。 这需要用户交互。
  • WritableStream API: 用于将数据写入文件。
  • fetch API: 用于发送 HTTP 请求,并支持 Range 请求头。
  • 错误处理: 需要处理网络错误和文件写入错误。
  • 进度显示: 可以在下载过程中更新进度条或显示下载进度。

浏览器兼容性: showSaveFilePickerWritableStream 是比较新的 API,需要检查浏览器兼容性。 对于不支持的浏览器,需要使用其他的文件保存方法。

后端配合: 服务器端需要正确处理 Range 请求头,并返回 206 Partial Content 状态码和 Content-Range 响应头。 大多数主流服务器软件都支持断点续传。

这个例子提供了一个基本的断点续传实现。 在实际应用中,你可能需要添加更多的功能,例如暂停/恢复下载、错误重试等。

posted @ 2024-11-27 09:00  王铁柱6  阅读(93)  评论(0)    收藏  举报