使用 Axios 下载文件并更新进度条
使用axios
的onDownloadProgress
回调函数实现下载文件,并更新下载进度条。
示例代码
import { ElMessage } from "element-plus";
import axios from "axios";
import type { AxiosResponse, AxiosProgressEvent } from "axios";
import { baseUrl } from "@/utils/baseUrl";
import type { FileInfo } from "@/interfaces";
const apiPrefix = "/api-file";
type ProgressCallback = (file: FileInfo, progress: number) => void;
// 防抖函数
function debounce<ProgressCallback extends (...args: any) => any>(
func: ProgressCallback,
wait: number
): ProgressCallback {
let startTime = Date.now();
return function (this: any, ...args: Parameters<ProgressCallback>) {
if (Date.now() - wait >= startTime) {
func.apply(this, args);
startTime = Date.now();
}
} as ProgressCallback;
}
export async function downloadFile(
file: FileInfo,
token: string | null,
updateProgressBar: ProgressCallback
): Promise<void> {
try {
const updateProgress = debounce(updateProgressBar, 500); // 500ms 防抖间隔时间
const response: AxiosResponse = await axios({
url: `${baseUrl}${apiPrefix}/files/${file.id}/`,
method: "GET",
responseType: "blob", // 接收二进制数据
headers: token ? { Authorization: "Bearer " + token } : {},
onDownloadProgress: (progressEvent: AxiosProgressEvent) => {
const total = progressEvent.total;
const current = progressEvent.loaded;
if (total) {
const percentage = Math.floor((current / total) * 100);
updateProgress(file, percentage);
}
},
});
if (response.headers["content-type"].startsWith("application/json")) {
const resCode = response.data.code;
if (resCode !== 0) {
ElMessage.warning(response.data.msg);
}
} else {
// 处理文件名,从响应头的 content-disposition 中获取
let filename = "";
const disposition = response.headers["content-disposition"];
const disposition = response.headers["content-disposition"];
if (disposition) {
const filenameRegex = /filename[^;=\n]*=((['"]).*?\2|[^;\n]*)/;
const matches = filenameRegex.exec(disposition);
if (matches && matches[1]) {
filename = matches[1].replace(/['"]/g, ""); // 去除引号
}
}
// 处理下载的文件
const urlBlob = window.URL.createObjectURL(new Blob([response.data]));
const link = document.createElement("a");
link.style.display = "none";
link.href = urlBlob;
link.download = filename; // 指定下载后的文件名,防止跳转
document.body.appendChild(link);
link.click();
window.URL.revokeObjectURL(urlBlob);
document.body.removeChild(link);
}
} catch (error) {
console.error("Error downloading the file:", error);
ElMessage.warning("下载文件失败,请稍后再试");
}
}
/**
* 更新页面中的进度条
*/
const updateProgressBar = (file: FileInfo, percentage: number) => {
file.downloading = true;
console.log(`Download progress: ${percentage}%`);
file.downloadingProgress = percentage;
};
代码讲解
1. 使用 axios
进行文件下载
使用axios
发送了一个GET
请求来下载文件,并指定了responseType
为blob
,以确保接收到的文件是二进制数据,并在请求头中传入 jwt token。
const response: AxiosResponse = await axios({
url: `${baseUrl}${apiPrefix}/files/${file.id}/`,
method: "GET",
responseType: "blob", // 接收二进制数据
headers: token ? { Authorization: "Bearer " + token } : {},
});
2. 实现下载进度的更新
通过axios
的onDownloadProgress
回调函数,可以获取下载的进度。回调函数在文件下载过程中不断触发,提供了loaded
和total
两个属性,分别代表已下载的字节数和总字节数。
onDownloadProgress: (progressEvent: AxiosProgressEvent) => {
const total = progressEvent.total;
const current = progressEvent.loaded;
if (total) {
const percentage = Math.floor((current / total) * 100);
updateProgress(file, percentage);
}
};
为了防止进度条更新过于频繁导致的性能问题,使用了一个简单的防抖函数debounce
,将更新进度的频率限制为 500 毫秒。
调用downloadFile
函数时,需要传入updateProgressBar
函数,在该函数中实现更新页面进度条操作。
/**
* 更新页面中的进度条
*/
const updateProgressBar = (file: FileInfo, percentage: number) => {
file.downloading = true;
console.log(`Download progress: ${percentage}%`);
file.downloadingProgress = percentage;
};
3. 文件处理与下载
在下载完成后,根据响应头中的Content-Disposition
获取文件名,然后创建了一个 URL 对象,并利用a
标签触发文件下载。
const urlBlob = window.URL.createObjectURL(new Blob([response.data]));
const link = document.createElement("a");
link.style.display = "none";
link.href = urlBlob;
link.download = filename; // 指定下载后的文件名,防止跳转
document.body.appendChild(link);
link.click();
window.URL.revokeObjectURL(urlBlob);
document.body.removeChild(link);
标签:Axios,const,进度条,axios,link,file,percentage,下载
From: https://www.cnblogs.com/shouwangrenjian/p/18359586