upload
大文件如何实现断点续传实现大文件的断点续传,可以通过以下步骤实现。这通常包括文件切片、上传控制和服务端合并等过程。以下是具体的实现步骤:
1. 实现原理
断点续传的核心思想是将文件切分为多个小块(chunk),分块上传,并记录每块的上传状态。如果上传中断,重新上传时可以从未完成的块继续上传,而不是重新上传整个文件。
2. 前端实现流程
(1) 文件切片
通过 File
和 Blob
对象,将大文件切分成固定大小的块。
function sliceFile(file, chunkSize = 2 * 1024 * 1024) { // 每块 2MB
const chunks = [];
let current = 0;
while (current < file.size) {
chunks.push(file.slice(current, current + chunkSize));
current += chunkSize;
}
return chunks;
}
(2) 计算文件的唯一标识
通过文件的内容生成一个唯一标识(如 hash
),确保服务端可以识别文件和对应的块。
async function calculateHash(file) {
const sparkMD5 = new SparkMD5.ArrayBuffer(); // 使用 SparkMD5 或其他库
const chunkSize = 2 * 1024 * 1024; // 2MB
const chunks = sliceFile(file, chunkSize);
for (const chunk of chunks) {
const buffer = await chunk.arrayBuffer();
sparkMD5.append(buffer);
}
return sparkMD5.end();
}
(3) 分块上传
使用 FormData
将每个块上传到服务器。
async function uploadChunk(file, chunk, index, hash) {
const formData = new FormData();
formData.append("file", chunk);
formData.append("filename", file.name);
formData.append("index", index);
formData.append("hash", hash);
return fetch("/upload", {
method: "POST",
body: formData,
});
}
(4) 检查已上传的块
在上传前,向服务器发送请求,获取已上传的块信息,避免重复上传。
async function getUploadedChunks(hash) {
const response = await fetch(`/upload/status?hash=${hash}`);
return response.json(); // 返回已上传的块列表
}
(5) 控制上传逻辑
利用 Promise.all
或 async/await
控制上传过程,并记录每块的上传状态。
async function uploadFile(file) {
const hash = await calculateHash(file);
const chunks = sliceFile(file);
const uploadedChunks = await getUploadedChunks(hash);
for (let i = 0; i < chunks.length; i++) {
if (uploadedChunks.includes(i)) {
console.log(`Chunk ${i} already uploaded`);
continue;
}
await uploadChunk(file, chunks[i], i, hash);
console.log(`Chunk ${i} uploaded`);
}
// 通知服务端合并文件
await fetch(`/upload/merge`, {
method: "POST",
body: JSON.stringify({ hash, filename: file.name }),
headers: { "Content-Type": "application/json" },
});
}
3. 服务端实现流程
(1) 接收文件块
- 使用
multipart/form-data
接收上传的文件块。 - 将每个文件块临时存储到服务器,命名时附带块索引和文件的
hash
。
(2) 记录上传状态
- 在服务器端记录已上传的块信息(如在数据库或缓存中存储)。
- 响应客户端的上传状态请求。
(3) 文件合并
- 在接收到所有文件块后,将它们按顺序合并成完整文件。
- 删除临时块文件,释放存储空间。
4. 断点续传的核心技术
文件切片
利用前端 File.slice
方法,将文件分成多个小块,便于上传和重传。
文件校验
通过 hash
或 MD5
校验,确保上传过程中数据完整。
状态记录
- 客户端记录上传进度,方便中断后重新开始。
- 服务端记录已上传块,避免重复上传。
并发上传
使用多线程并发上传多个文件块,提高上传速度。
5. 示例架构
前端
- 使用
HTML5
提供的File API
实现文件读取和切片。 - 使用
fetch
或axios
实现 HTTP 请求。
服务端
- 使用
Node.js
和Express
或其他框架处理文件块上传。 - 存储已上传的文件块和状态,提供文件合并接口。
6. 常见优化
- 并发上传控制:使用限制并发数量的工具(如
Promise.allSettled
)。 - 重试机制:在块上传失败时进行自动重试。
- 前端暂停/恢复:提供上传的暂停和恢复功能。
- 服务端资源清理:定期清理超时未完成的临时文件。
通过以上方法,可以实现高效、可靠的大文件断点续传。