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