fetch下载后端提供的文件
最近有这么一个需求,就是后端api地址返回一个文件,这个文件是已经格式化好的,比如表格.xlsx
,或者是其他文件zip这些。
但是后端他加了鉴权,所以如果直接a链接访问这个接口,我们无法在头信息上添加token字段,于是这个请求被作为无效。
然后我使用了axios的请求,结果返回的内容,转换为blob对象后,下载完文件就被破坏了,无法打开。
这里我贴一下之前的代码。
api().then(res=>{
let blob = new Blob([err]);
let a = document.createElement("a");
a.href = URL.createObjectURL(blob);
a.download = "表格文件.xlsx";
a.style.display = "none";
document.body.appendChild(a);
a.click();
URL.revokeObjectURL(a.href); // 释放URL 对象
a.remove();
}).catch(err=>{
console.log(err);
})
api是一个封装的axios对象,指定了url地址和自定义头信息,这里就不多说了,主要是文件的下载。
使用该方式,下载的文件无法打开。
后端返回的就是一个表格文件。
没办法,只能使用fetch
fetch("api地址",{
headers:{
token: this.$store.getters.token
},
method: "POST",
}).then(res=>{
return res.blob();
}).then(blob=>{
let a = document.createElement("a");
a.href = URL.createObjectURL(blob);
a.download = "表格文件.xlsx";
a.style.display = "none";
document.body.appendChild(a);
a.click();
URL.revokeObjectURL(a.href); // 释放URL 对象
a.remove();
}).catch(err=>{
console.log(err);
})
这样就能正确的下载该文件了,打开也无问题。
注意:
有的后端可能无法接收到json格式的数据,可以使用formdata,但是不要讲fetch的协议改为:'Content-Type': 'multipart/form-data'
fetch可以直接传formdata对象,如果你改成这种协议,你会发现上传的参数变得乱七八糟
知识补充
URL.createObjectURL
URL.createObjectURL()方法会生成一个地址,这个地址代表着根据blob对象所生成的资源入口,这个资源入口存放于浏览器的blob URL store 中。
其生成的url地址由四个部分组成:
- blob:
- origin(域名)
- / (斜杠)
- UUID
uuid每次都会随机生成,所以即便是下载同一个文件,这个链接地址也是不一样的。
例子:
blob:http://localhost:8080/b59340e5-2182-4607-815d-8ccaedbfe705
由于这个链接用完就不需要再保留,否则会在网页关闭之前一直保留,所以需要手动删除。
URL.revokeObjectURL(a.href);
res.blob
这是fetch的一个功能,在第一个then回调时,返回的是一个响应结果promise对象,如果是文本内容,我们需要使用return出res.json()来让下一个then接收到参数。
如果是文件,我们则使用res.blob()方法,它表示通过字节流读取器读取所有数据,然后包装成blob对象并返回。
然后下一个then就可以接收到已经转换好的blob对象,我们就可以通过URL.createObjectURL创建下载链接了。
每次调用 res.blob() 方法都会执行 “consume body” 动作,“consume body” 的流程大概是这样的:
- 获取字节流的读取器
- 通过读取器读取所有的数据
- 把数据包装成 blob 对象并返回
如果有兴趣可以看看这篇文章,他讲的比我更详细:
本文系作者 @木灵鱼儿 原创发布在木灵鱼儿站点。未经许可,禁止转载。
暂无评论数据