#在Web开发中,大文件上传一直是一个挑战。传统的文件上传方法可能导致浏览器崩溃、服务器过载或上传超时。为了解决这个问题,我们可以使用文件分片(Chunking)技术,将大文件分割成多个小块(chunks),然后逐个上传这些小块。这样不仅可以提高上传的稳定性,还可以实现断点续传和并行上传。#
分片上传流程
- 前端准备:使用JavaScript的
File
API和Blob.prototype.slice()
方法将文件分割成多个分片。 - 上传分片:通过Ajax(或Fetch API)等技术逐个上传分片到服务器。
- 服务端处理:服务器接收分片数据,并保存到临时位置。
- 合并分片:当所有分片上传完成后,服务器将所有分片合并成一个完整的文件。
- 验证与清理:验证合并后的文件完整性,并清理临时分片文件。
示例代码
前端代码(使用XMLHttpRequest和FormData进行分片上传):
function uploadFile(file, chunkSize = 1024 * 1024 * 5) { // 5MB per chunk
const totalChunks = Math.ceil(file.size / chunkSize);
let currentChunk = 0;
function uploadChunk(chunkStart, chunkEnd) {
const chunk = file.slice(chunkStart, chunkEnd);
const formData = new FormData();
formData.append('file', chunk);
formData.append('chunkNumber', currentChunk);
formData.append('chunkSize', chunkSize);
formData.append('totalChunks', totalChunks);
formData.append('fileName', file.name);
const xhr = new XMLHttpRequest();
xhr.open('POST', '/upload', true);
xhr.upload.onprogress = function(e) {
if (e.lengthComputable) {
console.log(`Chunk ${currentChunk + 1} uploaded: ${(e.loaded / e.total * 100).toFixed(2)}%`);
}
};
xhr.onload = function() {
if (xhr.status === 200) {
currentChunk++;
if (currentChunk < totalChunks) {
uploadChunk(chunkEnd, chunkStart + chunkSize * (currentChunk + 1));
} else {
console.log('All chunks uploaded successfully!');
}
} else {
console.error('Chunk upload failed:', xhr.statusText);
}
};
xhr.send(formData);
}
uploadChunk(0, chunkSize);
}
// 使用方法:
const fileInput = document.querySelector('input[type="file"]');
fileInput.addEventListener('change', function(e) {
const file = e.target.files[0];
if (file) {
uploadFile(file);
}
});
后端代码(这里以Node.js和Express为例,实际中可能需要结合数据库和其他技术来追踪上传状态和合并文件):
const express = require('express');
const fs = require('fs');
const path = require('path');
const app = express();
const uploadDir = './uploads'; // 临时存储分片的目录
app.post('/upload', (req, res) => {
const file = req.files.file; // 假设你使用了中间件来处理multipart/form-data请求
const chunkNumber = parseInt(req.body.chunkNumber, 10);
const chunkSize = parseInt(req.body.chunkSize, 10);
const totalChunks = parseInt(req.body.totalChunks, 10);
const fileName = req.body.fileName;
// 创建文件路径
const filePath = path.join(uploadDir, `${fileName}_${chunkNumber}`);
// 保存文件到临时位置
file.mv(filePath, (err) => {
if (err) {
return res.status(500).send(err);
}
// 这里可以添加代码来检查所有分片是否上传完成,并合并它们
res.send('Chunk uploaded successfully!');
});
});
// ... 其他路由和中间件配置 ...
app.listen(3000, () => {
console.log('Server listening on port 3000');
});
注意:上述示例仅用于演示目的,并未包含完整的错误处理和文件合并逻辑。在实际应用中,你需要添加更多的逻辑来实现