今天工作碰到一个需求,点击按钮导出excel,后端是直接返回的文件流,如下图:
方案一
直接用a标签来改造这个按钮,把下载地址放到href里,因为后端已经在响应头里设置了文件名和文件类型,点击按钮就能下载带有默认文件名的excel文件了。但是这个方案中,地址如果是动态的就不够灵活了。
方案二
按钮不变成a标签,在按钮的点击事件里处理
// 获取baseurl
click(){
const baseurl= `xxx`;
// 拼接上导出的地址,如果接口还需要其他参数,都可以直接拼接上
let url=`${baseurl}/xxx/export/${xxx}`
// 第二个参数'_self'表示在当前页下载,不打开新的页面
window.open(url,'_self')
}
方案三
直接处理文件流
axios({
method: '请求方法(get/post)',
url: '地址',
data: '请求参数',
responseType: 'blob' // 响应数据的类型要设置成blob,设置arraybuffer也可以,下文有解释
}).then((res) => {
// 解析文件名
const str = res.headers['content-disposition'].split(';')[1].split('=')[1];
const filename = decodeURIComponent(str);
// 用blob存储二进制文件
const blob = new Blob([res.data], {
type: 'application/vnd.ms-excel', // 设置文件类型 pdf是application/pdf,word是application/vnd.openxmlformats-officedocument.wordprocessingml.document,其他类型可以百度一下
});
// 创建一个临时的url指向blob对象
const objectUrl = window.URL.createObjectURL(blob);
// 创建url之后可以模拟对此文件对象的一系列操作,例如:预览、下载
const a = document.createElement('a');
a.setAttribute('href', objectUrl);
a.setAttribute('download', filename);
a.click();
// 5.释放这个临时的对象url
window.URL.revokeObjectURL(objectUrl);
}).catch(error => {
...
});
Blob(Binary Large Object)是用于表示大型二进制数据对象的 JavaScript 数据类型。它是一个不可变的原始数据对象,可以存储各种类型的数据,如图像、音频、视频和其他任意二进制数据。
Blob 对象和 ArrayBuffer 对象在某些方面相似,因为它们都可以用来存储二进制数据。但是,它们之间也存在一些重要的区别。
数据存储形式:ArrayBuffer 是一个连续的、固定长度的原始二进制数据缓冲区。它是在内存中分配一块指定长度的空间来存储数据。而 Blob 是一个非连续的二进制数据对象,它可以由多个片段(即 Blob 的数据块)组成。这意味着 Blob 对象可以由不同的数据来源进行构建,例如从文件、网络请求或其他 Blob 对象中创建。
可访问性:ArrayBuffer 对象提供了一种机制,通过 TypedArray 和 DataView 视图来直接读取和修改数据。而 Blob 对象并不直接暴露数据的内容,而是提供了一组异步方法(例如 FileReader)来读取其中的数据。
用途和应用场景:ArrayBuffer 主要用于在 JavaScript 中高效地处理和操作二进制数据,例如图像处理、音频解码、加密算法等。而 Blob 对象更适合用于处理文件、上传下载、数据传输等场景,因为它可以方便地保存和传递整个数据块,而不需要直接读取或修改其内容。
总结一下,ArrayBuffer 和 Blob 都是用于处理二进制数据的 JavaScript 数据类型。ArrayBuffer 是一个连续的固定长度二进制数据缓冲区,而 Blob 是一个非连续的二进制数据对象,可以由多个片段组成。ArrayBuffer 提供了直接读取和修改数据的能力,而 Blob 则适用于处理文件、上传下载和数据传输等场景。根据具体的使用需求,选择使用适合的数据类型来操作和处理二进制数据。
补充
最近开发时,和新的后端同学联调时发现要么下载的文件打不开,要么下载的文件是空白,研究了一下发现是后端代码少配置了几个属性,Access-Control-Expose-Headers
这个响应头的属性需要设置前端可见,Content-Type
要设置成对应的文件类型,Content-Disposition
数据处理方式和文件名也要处理一下。
下面代码是我用koa写的后端获取文件流示例代码,安装koa和koa2-cors的依赖后,把需要给前端的文件地址配置一下,就可以node index.js运行了,给前端的url就是http://localhost:3000。
文件名:index.js
const Koa = require('koa');
const cors = require('koa2-cors');
const fs = require('fs');
const path = require('path');
const app = new Koa();
app.use(cors());
// 让Content-Disposition在前端可见,需要设置Access-Control-Expose-Headers
app.use(async (ctx, next) => {
ctx.set('Access-Control-Expose-Headers', 'Content-Disposition');
await next();
});
app.use(async ctx => {
// 获取文件路径
const filePath = path.join(__dirname, './jianli.pdf'); // 你的文件地址
// 读取文件
const file = fs.readFileSync(filePath);
// 设置响应类型为pdf
ctx.set('Content-Type', 'application/pdf');
// 设置响应头,使其可以下载,你可以设置你想要的文件名
ctx.set('Content-Disposition', 'attachment; filename=jianli.pdf');
// 将文件内容赋值给response.body
ctx.body = file;
});
app.listen(3000, () => {
console.log('Server is running at http://localhost:3000');
});