木灵鱼儿
阅读:2296
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 对象并返回
如果有兴趣可以看看这篇文章,他讲的比我更详细:
版权申明
本文系作者 @木灵鱼儿 原创发布在木灵鱼儿 - 有梦就能远航站点。未经许可,禁止转载。
相关推荐
base64转file文件方法
使用canvas操作内容后,如果想保存图片之类的操作,就无可避免的要处理这一步,因为canvas导出的是base64格式的文件,如果你只做预览还好,存储的话,就要想办法了。我的想法是转成上传文件的那种file格式。方法如下:/** * @description: 将base64转换为文件对象 * @param {*} dataUrl base64 * @param {*} fileName 文件名 * @Date: 2021-06-30 14:33:47 * @Author: mulingyuer */ export function dataURLtoFile(dataUr...
目前前端下载文件的最佳实践
目前前端最佳的方案其实有两种:a元素下载iframe 无闪下载事实上这两种下载方式,其实都存在相同的一个问题,就是如果下载的文件是跨域的(不是同域名下的问题,或者其他原因);并且这个文件浏览器可以直接打开的,比如:图片、文本文件。那么浏览器会直接打开文件,并不是触发下载,而如果下载的文件是安装包,压缩包zip这些,则是触发下载。这个问题就很头疼。a元素下载的缺点a元素下载,那么就必须设置download属性,这个属性可以接收一个参数,可以是带后缀的文件名,或者不带后缀。也可以为空,但是要设。不带后缀的话文件格式就会与下载的文件保持一致,如果带了格式后缀,可能导致下载的jpg文件,你设置为...

fetch和ajax获取不到头信息的解决办法
今天就遇到一个问题,后端从头信息给我携带了数据,我需要在请求头中获取,但是不管怎么get,返回的永远是null,但是f12去看响应头,那个数据就在那,亮瞎了眼。一个大大的问号?why???谷歌查了下原因,大概就两种:安全限制,不允许客户端获取部分头信息跨域了,对于跨域请求,客户端允许获取的response header字段只限于“simple response header”和“Access-Control-Expose-Headers” ,在“Access-Control-Allow-Headers”中加了无效说到底,还是后端的设置,如果是nigix可以参考下面的代码:以token头信...
fetch 请求报错处理思路
之前写过一片使用fetch下载文件的方法,但是如果后端返回一个错误对象,使用response.blob()会将这个错误对象直接转为blob对象,然后被转为文件下载下来。但实际上我们是要区分处理的,比如是文件流我们就下载文件,是错误对象,我们就进行错误提示和抛出错误。所以这里,我主要分享下我对错误处理的思路。基础知识首先,在fetch第一个then回调中,我们可以对response对象进行三种方法操作:response.text 返回的是一个纯文本 是一个promise对象response.json 返回的是一个对象(json/array) 是一个promise对象response.b...
