vue大文件下载实现
Vue 大文件下载实现方案
前端分片下载
使用 axios 或 fetch 结合 Blob 对象实现分片下载,避免内存溢出。通过设置 Range 请求头控制下载范围。
async function downloadLargeFile(url, fileName) {
const chunkSize = 1024 * 1024 * 5; // 5MB分片
let startByte = 0;
let endByte = chunkSize;
const fileSize = await getFileSize(url); // 先获取文件总大小
while (startByte < fileSize) {
const response = await fetch(url, {
headers: { 'Range': `bytes=${startByte}-${endByte}` }
});
const blob = await response.blob();
saveChunk(blob, fileName, startByte === 0);
startByte = endByte + 1;
endByte = Math.min(startByte + chunkSize - 1, fileSize - 1);
}
}
function saveChunk(blob, fileName, isFirstChunk) {
const link = document.createElement('a');
link.href = URL.createObjectURL(blob);
link.download = fileName;
link.style.display = 'none';
document.body.appendChild(link);
link.click();
setTimeout(() => {
URL.revokeObjectURL(link.href);
document.body.removeChild(link);
}, 100);
}
服务端配合
服务端需支持 Range 请求,返回 206 Partial Content 状态码。Node.js 示例:

app.get('/download', (req, res) => {
const range = req.headers.range;
const filePath = 'large-file.zip';
const fileSize = fs.statSync(filePath).size;
if (range) {
const [start, end] = range.replace(/bytes=/, '').split('-');
const chunkStart = parseInt(start, 10);
const chunkEnd = end ? parseInt(end, 10) : fileSize - 1;
res.writeHead(206, {
'Content-Range': `bytes ${chunkStart}-${chunkEnd}/${fileSize}`,
'Accept-Ranges': 'bytes',
'Content-Length': chunkEnd - chunkStart + 1,
'Content-Type': 'application/octet-stream'
});
fs.createReadStream(filePath, { start: chunkStart, end: chunkEnd })
.pipe(res);
} else {
res.writeHead(200, {
'Content-Length': fileSize,
'Content-Type': 'application/octet-stream'
});
fs.createReadStream(filePath).pipe(res);
}
});
进度显示优化
通过监听 onprogress 事件显示下载进度:

axios.get(url, {
responseType: 'blob',
onDownloadProgress: progressEvent => {
const percent = Math.round(
(progressEvent.loaded * 100) / progressEvent.total
);
console.log(`下载进度: ${percent}%`);
}
}).then(response => {
const url = window.URL.createObjectURL(new Blob([response.data]));
const link = document.createElement('a');
link.href = url;
link.setAttribute('download', 'filename.ext');
document.body.appendChild(link);
link.click();
});
断点续传实现
利用 localStorage 存储已下载的字节位置:
let downloadedBytes = localStorage.getItem(fileName) || 0;
function resumeDownload(url, fileName) {
const chunkSize = 1024 * 1024 * 5;
let startByte = parseInt(downloadedBytes);
let endByte = startByte + chunkSize - 1;
fetch(url, {
headers: { 'Range': `bytes=${startByte}-${endByte}` }
}).then(response => {
// ...处理分片
localStorage.setItem(fileName, endByte + 1);
});
}
Web Worker 处理
将耗时的下载逻辑放入 Web Worker 避免阻塞 UI:
// worker.js
self.onmessage = function(e) {
const { url, fileName } = e.data;
downloadLargeFile(url, fileName).then(() => {
self.postMessage('done');
});
};
// Vue组件中
const worker = new Worker('worker.js');
worker.postMessage({ url, fileName });
worker.onmessage = (e) => {
if (e.data === 'done') console.log('下载完成');
};
注意事项
- 浏览器对 Blob 对象有内存限制,分片大小需根据实际情况调整
- 下载完成后及时调用
URL.revokeObjectURL()释放内存 - 服务端必须正确实现
Range请求处理 - 跨域请求需配置 CORS 和
Access-Control-Expose-Headers






