js实现分段上传
分段上传的实现方法
分段上传(Chunked Upload)是一种将大文件分割成多个小块分别上传的技术,常用于处理大文件上传或网络不稳定的场景。以下是使用JavaScript实现分段上传的几种方法:
使用XMLHttpRequest实现
XMLHttpRequest是传统的AJAX请求方式,可以通过设置请求头和数据分割实现分段上传。
function uploadFileInChunks(file, chunkSize) {
const totalChunks = Math.ceil(file.size / chunkSize);
let currentChunk = 0;
function uploadNextChunk() {
const start = currentChunk * chunkSize;
const end = Math.min(start + chunkSize, file.size);
const chunk = file.slice(start, end);
const xhr = new XMLHttpRequest();
xhr.open('POST', '/upload', true);
xhr.setRequestHeader('Content-Type', 'application/octet-stream');
xhr.setRequestHeader('X-Chunk-Number', currentChunk);
xhr.setRequestHeader('X-Total-Chunks', totalChunks);
xhr.setRequestHeader('X-File-Name', encodeURIComponent(file.name));
xhr.onload = function() {
if (xhr.status === 200) {
currentChunk++;
if (currentChunk < totalChunks) {
uploadNextChunk();
} else {
console.log('Upload complete');
}
}
};
xhr.send(chunk);
}
uploadNextChunk();
}
使用Fetch API实现
Fetch API提供了更现代的异步请求方式,结合Blob.slice()方法可以实现分段上传。
async function chunkedUpload(file, chunkSize = 1024 * 1024) {
const totalChunks = Math.ceil(file.size / chunkSize);
for (let i = 0; i < totalChunks; i++) {
const start = i * chunkSize;
const end = Math.min(start + chunkSize, file.size);
const chunk = file.slice(start, end);
const formData = new FormData();
formData.append('file', chunk, file.name);
formData.append('chunkIndex', i);
formData.append('totalChunks', totalChunks);
try {
const response = await fetch('/upload', {
method: 'POST',
body: formData
});
if (!response.ok) throw new Error('Upload failed');
} catch (error) {
console.error('Error uploading chunk:', error);
break;
}
}
}
使用Resumable.js库实现
Resumable.js是一个专门处理分段上传的JavaScript库,提供了更完善的解决方案。
const r = new Resumable({
target: '/upload',
chunkSize: 1 * 1024 * 1024,
simultaneousUploads: 3,
testChunks: true
});
r.assignBrowse(document.getElementById('browseButton'));
r.assignDrop(document.getElementById('dropTarget'));
r.on('fileAdded', function(file) {
r.upload();
});
r.on('fileSuccess', function(file) {
console.log(file.fileName + ' uploaded successfully');
});
r.on('fileError', function(file, message) {
console.log('Error uploading ' + file.fileName + ': ' + message);
});
服务器端处理要点
分段上传需要服务器端配合处理,通常需要考虑以下方面:
- 接收并存储每个文件块
- 验证每个块的完整性
- 合并所有块重建完整文件
- 处理上传中断后的恢复
- 提供上传进度查询接口
进度跟踪实现
可以通过监听xhr.upload.onprogress或使用Resumable.js内置事件跟踪上传进度。
xhr.upload.onprogress = function(e) {
if (e.lengthComputable) {
const percentComplete = (e.loaded / e.total) * 100;
console.log(percentComplete + '% uploaded');
}
};
错误处理和恢复
实现断点续传需要在客户端和服务器端记录上传状态:
- 客户端保存已上传的块信息
- 服务器端验证块完整性
- 上传前检查哪些块已经上传
// 检查服务器上已上传的块
async function checkUploadedChunks(file, totalChunks) {
const response = await fetch(`/upload-status?name=${encodeURIComponent(file.name)}`);
const { uploadedChunks } = await response.json();
return uploadedChunks;
}
性能优化建议
- 使用Web Workers处理大文件分割
- 并行上传多个块(注意服务器承受能力)
- 压缩文件块减少传输量
- 实现本地存储暂存上传状态
以上方法可以根据具体需求组合使用,实现高效可靠的分段上传功能。







