之前遇到一个文件过大下载链接断开的问题,刚开始增加超时时间,效果并不好,后来经过各方面研究,上传都可以分段上传,下载也可以,所以和后端配合,实现了分段下载功能,现在把axios如何实现分段下载逻辑,总结成方法,以便以后参考。
<template></template>
<script>
export default {
name: "download",
data() {
return {
percentage: -1, // 下载进度
};
},
methods: {
// 分段下载需要后端配合
download() {
// 下载地址
const url = "...";
const chunkSize = 1024 * 1024 * 100; // 单个分段大小,这里测试用100M
let filesTotalSize = chunkSize; // 安装包总大小,默认100M
let filesPages = 1; // 总共分几段下载
let filesCurrentPage = 0; // 第几段
let contentList = []; // 文件流数组
let sentAxios = (num) => {
let rande = chunkSize;
if (num) {
rande = `${(num - 1) * chunkSize + 2}-${num * chunkSize + 1}`;
} else {
// 第一次0-1方便获取总数,计算下载进度,每段下载字节范围区间
rande = "0-1";
}
let headers = {
range: rande,
};
this.axios({
method: "get",
url: url,
data: {},
headers: headers,
responseType: "blob",
onDownloadProgress: (a) => {
if (!num) {
return;
}
var percent = parseInt(
100 * ((a.loaded + 2 + (num - 1) * chunkSize) / filesTotalSize)
);
this.$nextTick(() => {
this.percentage = percent;
if (percent == 100) {
// 1秒后隐藏进度显示
setTimeout(() => {
this.percentage = -1;
}, 1000);
}
});
},
})
.then((response) => {
if (response.status == 200 || response.status == 206) {
//检查了下才发现,后端对文件流做了一层封装,所以将content指向response.data即可
const content = response.data;
// 获取文件总大小,方便计算下载百分比
filesTotalSize = response.headers["content-range"].split("/")[1];
// 计算总共页数,向上取整
filesPages = Math.ceil(filesTotalSize / chunkSize);
contentList.push(content); // 文件流数组
// 递归获取文件数据
if (filesCurrentPage < filesPages) {
filesCurrentPage++;
sentAxios(filesCurrentPage);
return;
}
//构造一个blob对象来处理数据
const reader = new FileReader();
reader.readAsText(response.data);
reader.onload = () => {
try {
// 如果返回的报文不是数据流,而是json,比如登录失效,执行下面逻辑
const res = JSON.parse(reader.result);
if (res.code === 401) {
// ...处理逻辑
}
} catch (err) {
const blob = new Blob(contentList);
// 文件名称
const fileName = response.fname;
//对于<a>标签,只有 Firefox 和 Chrome(内核) 支持 download 属性
//IE10以上支持blob但是依然不支持download
if ("download" in document.createElement("a")) {
//支持a标签download的浏览器
const link = document.createElement("a"); //创建a标签
link.download = fileName; //a标签添加属性
link.style.display = "none";
link.href = URL.createObjectURL(blob);
document.body.appendChild(link);
link.click(); //执行下载
URL.revokeObjectURL(link.href); //释放url
document.body.removeChild(link); //释放标签
} else {
//其他浏览器
navigator.msSaveBlob(blob, fileName);
}
this.$message.success("下载完成!");
}
}
} else {
this.$message.error("下载失败!");
}
})
.catch(function (error) {
console.log(error);
});
};
// 第一次获取数据方便获取总数
sentAxios(filesCurrentPage);
},
},
};
</script>