使用 Axios 下载文件并更新进度条
使用 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);
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】博客园社区专享云产品让利特惠,阿里云新客6.5折上折
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 【.NET】调用本地 Deepseek 模型
· CSnakes vs Python.NET:高效嵌入与灵活互通的跨语言方案对比
· DeepSeek “源神”启动!「GitHub 热点速览」
· Plotly.NET 一个为 .NET 打造的强大开源交互式图表库
· 我与微信审核的“相爱相杀”看个人小程序副业