使用 Axios 下载文件并更新进度条

使用 Axios 下载文件并更新进度条

使用axiosonDownloadProgress回调函数实现下载文件,并更新下载进度条。

示例代码

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请求来下载文件,并指定了responseTypeblob,以确保接收到的文件是二进制数据,并在请求头中传入 jwt token。

const response: AxiosResponse = await axios({
url: `${baseUrl}${apiPrefix}/files/${file.id}/`,
method: "GET",
responseType: "blob", // 接收二进制数据
headers: token ? { Authorization: "Bearer " + token } : {},
});

2. 实现下载进度的更新

通过axiosonDownloadProgress回调函数,可以获取下载的进度。回调函数在文件下载过程中不断触发,提供了loadedtotal两个属性,分别代表已下载的字节数和总字节数。

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);
posted @   守望人间  阅读(750)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 【.NET】调用本地 Deepseek 模型
· CSnakes vs Python.NET:高效嵌入与灵活互通的跨语言方案对比
· DeepSeek “源神”启动!「GitHub 热点速览」
· Plotly.NET 一个为 .NET 打造的强大开源交互式图表库
· 我与微信审核的“相爱相杀”看个人小程序副业
点击右上角即可分享
微信分享提示