最近遇到了一个需求,是需要前端通过Url去下载文件,于是研究了一波,便想着跟大家分享一下。 废话不多说,我们直接开始正文。
1.链接强制下载
最简单方式就是需要让服务端,给这个下载地址设置response header,使得url具有强制下载属性。 具体的设置:
1Content-Disposition: attachment; filename="image.jpg"
这个header的意思是设置文件显示方式为直接下载,默认的文件名为image.jpg。
这里简单介绍下Content-Disposition:
Content-Disposition是 MIME 协议的扩展,MIME 协议指示 MIME 用户代理如何显示附加的文件。它有两个值:inline (默认值)将文件内容直接显示在页面、attachment 弹出对话框让用户下载。
2.a标签下载
a标签下载是最简单的方式,只需要给a标签附加download属性即可。
1<a href="https://example.jpg" download="demo.jpg"></a>
这个a标签的意思是点击下载href中地址的文件,并默认文件名为demo.jpg。如果你不需要自定义名字也可以只写download属性,不要带后面的内容。
一切都是那么的美好,但是简单的代价就是有缺陷,这种方式会存在跨域问题。
3.a标签下载(但完全体)
为了解决跨域问题,我们只能另辟蹊径,不能只用一个a标签了。没办法,只能使大招了!
1const download = async (url) => {
2
3 const fileName = url.substring(url.lastIndexOf('/') + 1)
4
5 const response = await fetch(url);
6 if (!response.ok) {
7 throw new Error('请求下载文件地址Error');
8 }
9
10 const blob = await response.blob();
11
12 const urlBlob = window.URL.createObjectURL(blob);
13
14 const a = document.createElement('a');
15 a.href = urlBlob;
16
17 a.download = filename;
18 document.body.appendChild(a);
19 a.click();
20 document.body.removeChild(a);
21
22
23 window.URL.revokeObjectURL(urlBlob);
24}
细心的小伙伴发现了,这啥呀,这不还是用了a标签下载吗?确实确实,我们最终的方式还是用了a标签下载,我们先获取文件内容然后转成二进制,又把二进制转成了url。绕了一圈我们又回来了,但是这么做的目的就是为了解决跨域问题!
你发现这和我们人生一样,兜兜转转几十年我们又回到了起点,好似回到了我们刚出生的时候,一无所有,但又拥有者最美好的东西。
总结
设置Content-Disposition局限性太大了,不太推荐。
如果不存在跨域问题就直接a标签下载。
如果存在跨域,就上终极解决方案,绕圈圈!
2024/09/30 注意:await fetch(url)也有跨域问题,需要给oss设置允许跨域