最近遇到了一个需求,是需要前端通过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设置允许跨域

个人笔记记录 2021 ~ 2025