前端如何通过 Blob 下载 Excel 文件
后端接口返回 Blob 数据流下载 Excel 文件流程
📌 前提条件:
- 后端返回的是一个 Excel 文件流(Blob)
- 你的接口请求使用了 axios
🔁 步骤 1:设置请求响应类型为 Blob
在发起请求时,配置 responseType: 'blob'
,确保后端返回的数据以二进制流形式接收。示例(以 Axios 为例):
axios.get('/api/download-excel', {params: {},responseType: 'blob'
})
🧾 步骤 2:将响应数据转换为 Blob 对象
接收到响应后,用 new Blob()
封装二进制数据,并指定文件类型为 Excel 格式:
const blob = new Blob([res.data], {type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'
});
res.data
:就是后端返回的原始二进制数据type
:指定为 Excel 的 MIME 类型(推荐)
🔗 步骤 3:创建临时下载链接
通过 URL.createObjectURL()
创建指向 Blob 的临时链接:
const downloadUrl = window.URL.createObjectURL(blob);
这个链接是浏览器内部生成的,不会真正请求服务器。
📥 步骤 4:创建 <a>
标签并模拟点击
动态生成 <a>
标签,设置 href
为临时链接,添加 download
属性指定文件名,并模拟点击:
const link = document.createElement('a');
link.href = downloadUrl;
link.download = 'data.xlsx';
document.body.appendChild(link);
link.click();
🧹 步骤 5 & 6:清理内存中的对象 URL 和移除 <a>
标签
使用 URL.revokeObjectURL()
清理内存,避免资源泄漏:
window.URL.revokeObjectURL(downloadUrl); // 清理对象 URL
document.body.removeChild(link); // 移除 <a> 标签
完整代码示例
axios.get('/api/download-excel', {params: {},responseType: 'blob'
}).then(res => {const blob = new Blob([res.data], {type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'});const downloadUrl = window.URL.createObjectURL(blob);const link = document.createElement('a');link.href = downloadUrl;link.download = 'data.xlsx';document.body.appendChild(link);link.click();window.URL.revokeObjectURL(downloadUrl);document.body.removeChild(link);
});
🧪 补充说明:如何从响应头获取文件名?
有些后端会在响应头里返回文件名,例如:
Content-Disposition: attachment; filename="预充值记录-20240710.xlsx"
你可以提取出来作为下载文件名:
const disposition = res.headers['content-disposition'];
let filename = '预充值记录.xlsx';if (disposition && disposition.indexOf('filename=') !== -1) {const matches = /filename="?([^"]+)"?/.exec(disposition);if (matches.length > 1) {filename = decodeURIComponent(matches[1]);}
}
然后传给 download
属性:
link.setAttribute('download', filename);
🛠 如果你想统一封装一个下载函数(推荐)
你可以写一个通用函数来处理下载:
function downloadFile(url, method = 'get', data = {}, filename = '文件.xlsx') {return sendPost(url, data, method, {}, {}, {responseType: 'blob'}).then(res => {const blob = new Blob([res.data]);const downloadUrl = window.URL.createObjectURL(blob);const link = document.createElement('a');link.href = downloadUrl;link.setAttribute('download', filename);document.body.appendChild(link);link.click();window.URL.revokeObjectURL(downloadUrl);document.body.removeChild(link);});
}
使用示例:
downloadFile('/user/user/prepay/log', 'get', {created_time_start: '2024-07-01',created_time_end: '2024-07-10',excel: true
}, '预充值记录.xlsx');
🚫 常见错误排查
错误 | 原因 | 解决方案 |
---|---|---|
下载的是乱码文件 | 没有正确设置 responseType: 'blob' | 确保设置了 |
下载失败或空白 | 没处理错误响应(比如 JSON 错误信息被当成了 Blob) | 加判断是否为 Blob,或统一用 Blob.type 判断 |
文件名乱码 | 没解码中文文件名 | 使用 decodeURIComponent |
内存占用高 | 没调用 revokeObjectURL | 一定要清理 |
✅ 总结:完整流程图
步骤 | 说明 |
---|---|
1️⃣ responseType: 'blob' | 请求时配置,接收二进制数据 |
2️⃣ new Blob([res.data]) | 创建 Blob 对象 |
3️⃣ URL.createObjectURL(blob) | 创建临时下载链接 |
4️⃣ 创建 <a> 标签并点击 | 触发浏览器下载行为 |
5️⃣ URL.revokeObjectURL() | 清理内存 |
6️⃣ removeChild(link) | 移除动态创建的标签 |