你知道断点续传的原理吗?用js怎么实现?
我知道断点续传的原理。它主要依靠 HTTP 协议中的一些特性来实现。核心思想是将一个大文件分成多个小块,客户端每次只请求一部分数据,并在服务器端记录已下载的部分。如果下载中断,客户端可以根据已下载的记录,从中断的地方继续下载,避免重复下载已完成的部分。
以下是断点续传的原理和用 JavaScript 实现的方法:
原理:
-
分块请求: 客户端将文件分成多个小块,并记录每个块的大小和起始位置。
-
Range 请求头: 客户端使用 HTTP 请求头
Range
指定要下载的字节范围。例如,Range: bytes=0-999
表示请求文件的第一个 1000 字节。 -
服务器响应: 服务器收到带有
Range
请求头的请求后,会返回状态码206 Partial Content
和请求的字节范围,并在响应头Content-Range
中指明返回数据的范围和文件总大小。 -
客户端记录: 客户端收到响应后,将下载的数据块写入本地文件,并记录已下载的字节范围。
-
断点续传: 如果下载中断,客户端重新发送请求,并在
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
请求头。- 错误处理: 需要处理网络错误和文件写入错误。
- 进度显示: 可以在下载过程中更新进度条或显示下载进度。
浏览器兼容性: showSaveFilePicker
和 WritableStream
是比较新的 API,需要检查浏览器兼容性。 对于不支持的浏览器,需要使用其他的文件保存方法。
后端配合: 服务器端需要正确处理 Range
请求头,并返回 206 Partial Content
状态码和 Content-Range
响应头。 大多数主流服务器软件都支持断点续传。
这个例子提供了一个基本的断点续传实现。 在实际应用中,你可能需要添加更多的功能,例如暂停/恢复下载、错误重试等。