通过JavaScript下载文件到本地的方法(单文件)
最近在做一个文件下载的功能,这里把做的过程中用的技术和坑简要总结下。
1.单文件下载(a标签)
同源单文件
针对单文件的情况下,同源的文件,可以通过标签的download属性下载文件
constelt=document.createElement('a'); elt.setAttribute('href',url); elt.setAttribute('download','file.png'); elt.style.display='none'; document.body.appendChild(elt); elt.click(); document.body.removeChild(elt);
但是这个方案并不适用于非同源的资源,此时它相当于普通的超链接,点击会跳转到资源页面,而不是下载。
非同源图片
如果不存在CORS问题,可以借助Blob实现下载(构造xhr请求文件地址,以Blob的形式接收Response):
functiondownloadWithBlob(url){ fetch(url).then(res=>res.blob().then(blob=>{ vara=document.createElement('a'); varurl=window.URL.createObjectURL(blob); varfilename='file.png'; a.href=url; a.download=filename; a.click(); window.URL.revokeObjectURL(url); })); }
如果存在CORS问题,可以考虑使用canvas将图片转换成base64编码之后再通过标签的download属性下载
functiondownloadPic(url){ constimg=newImage; constcanvas=document.createElement('canvas'); constctx=canvas.getContext('2d'); img.onload=function(){ canvas.width=this.width; canvas.height=this.height; ctx.drawImage(this,0,0); constelt=document.createElement('a'); elt.setAttribute('href',canvas.toDataURL('image/png')); elt.setAttribute('download','file.png'); elt.style.display='none'; document.body.appendChild(elt); elt.click(); document.body.removeChild(elt); }; img.crossOrigin='anonymous'; img.src=url; }
2.单文件下载(iframe)
iframe方式是在页面内隐藏iframe,然后将下载地址加载到iframe中,从而触发浏览器的下载行为
constiframe=document.createElement('iframe'); iframe.src=url; iframe.style.display='none'; document.body.appendChild(iframe);
但是这里发现,即使是同域的图片,也无法完成下载,这是为啥呢?
这里就有个上面的a链接下载没有提到的问题:什么样的链接才能触发浏览器的下载:
url如何触发浏览器自动下载
一个url能否触发浏览器自动下载,主要看该请求响应头responseheader是否满足,一般是看Content-Disposition和Content-Type这两个消息头:
- responseheader中指定了Content-Disposition为attachment,它表示让浏览器把消息体以附件的形式下载并保存到本地(一般还会指定filename,下载的文件名默认就是filename)
- responseheader中指定了Content-Type为application/octet-stream(无类型)或application/zip(zip包时)等等。(其中application/octet-stream表示httpresponse为二进制流(没指定明确的type),用在未知的应用程序文件,浏览器一般不会自动执行或询问执行。浏览器会像对待设置了HTTP头Content-Disposition值为attachment的文件一样来对待这类文件)
只要url满足上述触发的要求,那么都可以通过iframe的形式来下载
3.代理服务处理下载
如果后端自己也能控制的话,或者后端能配合的话,可以写一个代理服务,在后端去请求文件数据,然后设置好相应的responseheader,然后前端请求代理服务来做下载。
前端(假设代理服务接口是http://exampale.com/download):
constdownloadUrl='http://exampale.com/download?url='+encodeURIComponent(url)+'&name=xxx'; constelt=document.createElement('a'); elt.setAttribute('href',downloadUrl); elt.setAttribute('download','file.png'); ...
后端
consturl=decodeURIComponent(req.query.url); http.get(url,(response)=>{ res.setHeader('Content-disposition','attachment;filename='+req.query.name); res.setHeader('Content-type','application/octet-stream'); response.pipe(res); });
单文件的处理先写到这里,多文件的下载下篇在写。
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持毛票票。
声明:本文内容来源于网络,版权归原作者所有,内容由互联网用户自发贡献自行上传,本网站不拥有所有权,未作人工编辑处理,也不承担相关法律责任。如果您发现有涉嫌版权的内容,欢迎发送邮件至:czq8825#qq.com(发邮件时,请将#更换为@)进行举报,并提供相关证据,一经查实,本站将立刻删除涉嫌侵权内容。