后端返回了 xlsx 文件流,前端怎么下载处理
当后端返回一个 .xlsx
文件流时,前端可以通过 JavaScript 处理这个文件流并触发浏览器下载。
实现步骤
-
发送请求获取文件流:
使用fetch
或axios
等工具向后端发送请求,确保响应类型设置为blob
(二进制数据流)。 -
创建 Blob 对象:
将返回的文件流转换为Blob
对象,这是处理二进制数据的标准方式。 -
生成下载链接:
使用URL.createObjectURL
方法将Blob
对象转换为一个临时 URL。 -
触发下载:
动态创建一个<a>
标签,设置其href
属性为生成的临时 URL,并调用click()
方法触发下载。 -
清理资源:
下载完成后,使用URL.revokeObjectURL
释放生成的临时 URL,避免内存泄漏。
使用 axios
实现
如果你使用的是 axios
,可以这样实现:
import axios from 'axios';
const downloadXlsx = async () => {
try {
// 发送请求并获取文件流
const response = await axios.get('/api/download-xlsx', {
responseType: 'blob', // 确保响应类型为 blob
headers: {
'Authorization': 'Bearer your_token_here', // 如果需要携带认证信息
},
});
// 创建 Blob 对象
const blob = new Blob([response.data], { type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' });
// 创建临时 URL
const url = window.URL.createObjectURL(blob);
// 创建 <a> 标签并触发下载
const a = document.createElement('a');
a.href = url;
a.download = 'example.xlsx'; // 设置下载文件名
document.body.appendChild(a); // 将 <a> 添加到 DOM 中(可选)
a.click(); // 触发点击事件
// 清理资源
window.URL.revokeObjectURL(url);
a.remove(); // 移除 <a> 标签
} catch (error) {
console.error('下载文件时发生错误:', error.message || '未知错误');
}
};
// 调用函数
downloadXlsx();
responseType: 'blob'
的含义
responseType
是 Axios 提供的一个配置选项,用于告诉 Axios 如何解析服务器返回的数据。- 当设置为
'blob'
时,表示你期望服务器返回的数据是一个二进制大对象(Binary Large Object,简称 Blob)。
Blob 是什么?
- Blob 是一种数据类型,通常用来表示不可变的、原始数据的类文件对象。
- 它可以包含文本、图像、音频、视频等二进制数据,或者混合内容。
- 在前端开发中,Blob 常用于处理文件下载、图片预览、或者将数据保存为文件。
为什么需要 responseType: 'blob'
?
当从服务器请求文件(如 Excel 文件、PDF 文件、图片等)时,服务器通常会返回二进制数据。如果直接使用默认的 responseType
(通常是 'json'
),Axios 会尝试将响应数据解析为 JSON 格式,这会导致错误或数据损坏。
通过设置 responseType: 'blob'
,你可以确保 Axios 正确地将响应数据作为二进制数据处理,而不会尝试将其解析为其他格式(如 JSON 或文本)。
代码的作用
const response = await axios({
url: '/api/download-xlsx',
method: 'GET',
responseType: 'blob', // 指定响应数据为 Blob 类型
});
-
发起 GET 请求:
- 向
/api/download-xlsx
发起一个 GET 请求,通常用于下载文件(例如 Excel 文件)。
- 向
-
指定响应类型:
- 设置
responseType: 'blob'
,告诉 Axios 将服务器返回的数据解析为 Blob 对象。
- 设置
-
处理响应数据:
- 返回的
response.data
将是一个 Blob 对象,代表下载的文件内容。
- 返回的
使用 fetch
实现
const downloadXlsx = async () => {
try {
// 发送请求并获取文件流
const response = await fetch('/api/download-xlsx', {
method: 'GET',
headers: {
'Authorization': 'Bearer your_token_here', // 如果需要携带认证信息
},
});
// 检查响应是否成功
if (!response.ok) {
throw new Error(`HTTP error! Status: ${response.status}`);
}
// 获取 blob 数据
const blob = await response.blob();
// 创建临时 URL
const url = window.URL.createObjectURL(blob);
// 创建 <a> 标签并触发下载
const a = document.createElement('a');
a.href = url;
a.download = 'example.xlsx'; // 设置下载文件名
document.body.appendChild(a); // 将 <a> 添加到 DOM 中(可选)
a.click(); // 触发点击事件
// 清理资源
window.URL.revokeObjectURL(url);
a.remove(); // 移除 <a> 标签
} catch (error) {
console.error('下载文件时发生错误:', error.message || '未知错误');
}
};
// 调用函数
downloadXlsx();
1. 定义异步函数
javascript
深色版本
const downloadXlsx = async () => {
async
关键字表示这是一个异步函数。- 异步函数允许使用
await
来等待异步操作(如网络请求)完成。
2. 发起 HTTP 请求
const response = await fetch('/api/download-xlsx', {
method: 'GET',
headers: {
'Authorization': 'Bearer your_token_here', // 如果需要携带认证信息
},
});
-
使用
fetch
发起一个 GET 请求到/api/download-xlsx
。 -
headers
部分用于设置请求头:'Authorization'
是一个常见的请求头字段,用于传递用户的身份验证信息(如 JWT Token)。- 如果 API 不需要认证,可以省略
headers
。
3. 检查响应状态
if (!response.ok) {
throw new Error(`HTTP error! Status: ${response.status}`);
}
response.ok
是一个布尔值,表示 HTTP 响应的状态码是否在 200-299 范围内。- 如果响应失败(如 404 或 500 错误),会抛出一个错误,并终止后续代码执行。
- 抛出的错误会被
catch
块捕获。
4. 获取 Blob 数据
const blob = await response.blob();
response.blob()
将响应数据解析为一个Blob
对象。- Blob 是一种二进制数据类型,通常用来表示文件内容。
await
确保在继续执行后续代码之前,blob
数据已经被完全加载。
5. 创建临时 URL
const url = window.URL.createObjectURL(blob);
window.URL.createObjectURL(blob)
创建一个指向Blob
的临时 URL。- 这个 URL 可以被用作
<a>
标签的href
属性,从而触发文件下载。
6. 创建 <a>
标签并触发下载
const a = document.createElement('a');
a.href = url;
a.download = 'example.xlsx'; // 设置下载文件名
document.body.appendChild(a); // 将 <a> 添加到 DOM 中(可选)
a.click(); // 触发点击事件
-
创建
<a>
标签:- 使用
document.createElement('a')
动态创建一个<a>
元素。
- 使用
-
设置
<a>
标签属性:href
:设置为前面生成的临时 URL。download
:指定下载文件的名称(如example.xlsx
)。
-
添加到 DOM 并触发点击:
- 将
<a>
标签添加到文档中(虽然不是必须,但某些浏览器可能需要这样做)。 - 使用
a.click()
模拟用户点击,从而触发文件下载。
- 将
7. 清理资源
window.URL.revokeObjectURL(url);
a.remove();
-
释放临时 URL:
- 使用
window.URL.revokeObjectURL(url)
释放前面创建的临时 URL,避免内存泄漏。
- 使用
-
移除
<a>
标签:- 使用
a.remove()
从 DOM 中移除<a>
标签,保持页面整洁。
- 使用
8. 错误处理
} catch (error) {
console.error('下载文件时发生错误:', error.message || '未知错误');
}
catch
块 用于捕获和处理可能出现的错误。- 如果在
try
块中的任何一步发生错误(如网络问题、API 返回错误等),都会进入catch
块。 - 使用
console.error
打印错误信息,方便调试。
9. 调用函数
downloadXlsx();
- 最后调用
downloadXlsx
函数,触发整个文件下载流程。
适用场景
- 下载动态生成的文件(如 Excel 表格、PDF 文档等)。
- 需要通过 API 获取文件内容并提供给用户下载的场景。
注意事项
-
跨域问题:
- 如果 API 存在跨域限制,需要确保服务器配置了正确的 CORS(跨域资源共享)策略。
-
大文件下载:
- 对于非常大的文件,可能需要考虑分块下载或流式处理,以避免内存占用过高。
-
浏览器兼容性:
fetch
和Blob
在现代浏览器中广泛支持,但在一些老旧浏览器中可能需要使用XMLHttpRequest
替代。
关键点说明
-
设置正确的 MIME 类型:
.xlsx
文件的 MIME 类型是application/vnd.openxmlformats-officedocument.spreadsheetml.sheet
。- 如果后端未正确设置 MIME 类型,前端可以通过
Blob
的第二个参数手动指定。
-
动态文件名:
- 如果后端在响应头中提供了文件名(例如通过
Content-Disposition
),可以通过解析响应头来动态设置文件名。 - 示例:
const contentDisposition = response.headers['content-disposition']; let fileName = 'example.xlsx'; if (contentDisposition && contentDisposition.includes('filename=')) { fileName = contentDisposition.split('filename=')[1].split(';')[0]; }
- 如果后端在响应头中提供了文件名(例如通过
-
错误处理:
- 在实际开发中,务必对请求错误进行处理,例如检查 HTTP 状态码是否为 200,或者捕获网络异常。
-
兼容性:
- 上述方法适用于现代浏览器(如 Chrome、Firefox、Edge、Safari)。如果需要支持旧版浏览器,可能需要引入
FileSaver.js
库。
- 上述方法适用于现代浏览器(如 Chrome、Firefox、Edge、Safari)。如果需要支持旧版浏览器,可能需要引入
使用 FileSaver.js 简化操作
如果你希望简化文件下载逻辑,可以使用第三方库 file-saver
。安装后,只需几行代码即可完成下载。
安装
npm install file-saver
使用示例
import { saveAs } from 'file-saver';
import axios from 'axios';
const downloadXlsx = async () => {
try {
const response = await axios({
url: '/api/download-xlsx',
method: 'GET',
responseType: 'blob',
});
// 使用 FileSaver.js 保存文件
saveAs(response.data, 'example.xlsx');
} catch (error) {
console.error('下载失败:', error);
}
};
// 调用函数
downloadXlsx();
总结
- 核心步骤:获取文件流 -> 转换为 Blob -> 创建临时 URL -> 触发下载 -> 清理资源。
- 推荐工具:
fetch
或axios
可以轻松获取文件流,FileSaver.js
可以进一步简化代码。 - 注意事项:确保后端返回的文件流格式正确,前端设置合适的 MIME 类型和文件名。
axios 处理
try {
const response = await axios({
url: '/api/download-xlsx',
method: 'GET',
responseType: 'blob', // 一定要注意请求时加此方法
});
getExportListApi(exportCarryData).then((res) => {
// 创建一个a标签
const link = document.createElement('a');
const url = window.URL.create0bjectURL(new Blob([res.data]));
link.href = url;
link.setAttribute('download', exportfile);
document.body.appendChild(link);
link.click();
// 销毁a标签
document.body.removeChild(link); window.URL.revoke0bjectURL(url);
message.success('导出成功!');
});