通过JavaScript下载文件到本地的方法(单文件)


Posted in Javascript onMarch 17, 2019

最近在做一个文件下载的功能,这里把做的过程中用的技术和坑简要总结下。

1. 单文件下载(a标签)

同源单文件

针对单文件的情况下,同源的文件,可以通过 < a> 标签的 download 属性下载文件

const elt = 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):

function downloadWithBlob(url) {
 fetch(url).then(res => res.blob().then(blob => {
  var a = document.createElement('a');
  var url = window.URL.createObjectURL(blob);
  var filename = 'file.png';
  a.href = url;
  a.download = filename;
  a.click();
  window.URL.revokeObjectURL(url);
 }));
}

如果存在CORS问题,可以考虑使用 canvas 将图片转换成 base64 编码之后再通过 标签的 download 属性下载

function downloadPic(url) {
 const img = new Image;
 const canvas = document.createElement('canvas');
 const ctx = canvas.getContext('2d');
 img.onload = function() {
  canvas.width = this.width;
  canvas.height = this.height;
  ctx.drawImage(this, 0, 0);

  const elt = 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中, 从而触发浏览器的下载行为

const iframe = document.createElement('iframe');
 iframe.src = url;
 iframe.style.display = 'none';
 document.body.appendChild(iframe);

但是这里发现,即使是同域的图片,也无法完成下载,这是为啥呢?

这里就有个上面的a链接下载没有提到的问题:什么样的链接才能触发浏览器的下载:

url如何触发浏览器自动下载

一个url能否触发浏览器自动下载,主要看该请求响应头response header是否满足,一般是看Content-Disposition和Content-Type这两个消息头:

  • response header中指定了Content-Disposition为attachment,它表示让浏览器把消息体以附件的形式下载并保存到本地 (一般还会指定filename, 下载的文件名默认就是filename)
  • response header中指定了Content-Type 为 application/octet-stream(无类型) 或 application/zip(zip包时)等等。(其中 application/octet-stream表示http response为二进制流(没指定明确的type), 用在未知的应用程序文件,浏览器一般不会自动执行或询问执行。浏览器会像对待 设置了HTTP头Content-Disposition 值为 attachment 的文件一样来对待这类文件)

只要url满足上述触发的要求,那么都可以通过iframe的形式来下载

3. 代理服务处理下载

如果后端自己也能控制的话,或者后端能配合的话,可以写一个代理服务,在后端去请求文件数据,然后设置好相应的response header, 然后前端请求代理服务来做下载。

前端(假设代理服务接口是http://exampale.com/download):

const downloadUrl = 'http://exampale.com/download?url=' + encodeURIComponent(url) + '&name=xxx';
 const elt = document.createElement('a');
 elt.setAttribute('href', downloadUrl);
 elt.setAttribute('download', 'file.png');
 ...

后端

const url = 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);
});

单文件的处理先写到这里,多文件的下载下篇在写。

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持三水点靠木。

Javascript 相关文章推荐
简单的JS多重继承示例
Mar 13 Javascript
jQuery中add实现同时选择两个id对象
Oct 22 Javascript
Jquery获取元素的父容器对象示例代码
Feb 10 Javascript
jquery淡化版banner异步图片文字效果切换图片特效
Apr 08 Javascript
js实现点击向下展开的下拉菜单效果代码
Sep 01 Javascript
浅谈js多维数组和hash数组定义和使用
Jul 27 Javascript
js Canvas实现的日历时钟案例分享
Dec 25 Javascript
vue中路由验证和相应拦截的使用详解
Dec 13 Javascript
Angular实现的table表格排序功能完整示例
Dec 22 Javascript
基于Vue自定义指令实现按钮级权限控制思路详解
May 23 Javascript
vue axios数据请求get、post方法及实例详解
Sep 11 Javascript
微信小程序实现tab左右切换效果
Nov 15 Javascript
微信小程序登录session的使用
Mar 17 #Javascript
Javascript读写cookie的实例源码
Mar 16 #Javascript
vue自定义键盘信息、监听数据变化的方法示例【基于vm.$watch】
Mar 16 #Javascript
vue自定义指令用法经典实例小结
Mar 16 #Javascript
简单易扩展可控性强的Jquery转盘抽奖程序
Mar 16 #jQuery
基于vue通用表单解决方案的思考与分析
Mar 16 #Javascript
vue+php实现的微博留言功能示例
Mar 16 #Javascript
You might like
php 文件上传代码(限制jpg文件)
2010/01/05 PHP
PHP调用Linux命令权限不足问题解决方法
2015/02/07 PHP
php实现encode64编码类实例
2015/03/24 PHP
TP5框架实现自定义分页样式的方法示例
2020/04/05 PHP
通过 Dom 方法提高 innerHTML 性能
2008/03/26 Javascript
javascript Split方法,indexOf方法、lastIndexOf 方法和substring 方法
2009/03/21 Javascript
如何使用jquery控制CSS样式,并且取消Css样式(如背景色,有实例)
2013/07/09 Javascript
详解AngularJS中ng-src指令的使用
2016/09/07 Javascript
JavaScript中如何使用cookie实现记住密码功能及cookie相关函数介绍
2016/11/10 Javascript
javascript 定时器工作原理分析
2016/12/03 Javascript
使用bat打开多个cmd窗口执行gulp、node
2017/02/17 Javascript
JAVA中截取字符串substring用法详解
2017/04/14 Javascript
Node.js实现发送邮件功能
2017/11/06 Javascript
JS获取input[file]的值并显示在页面的实现方法
2018/03/09 Javascript
jQuery中元素选择器(element)简单用法示例
2018/05/14 jQuery
从组件封装看Vue的作用域插槽的实现
2019/02/12 Javascript
vue项目中使用scss的方法步骤
2019/05/16 Javascript
vue读取本地的excel文件并显示在网页上方法示例
2019/05/29 Javascript
jstree中的checkbox默认选中和隐藏示例代码
2019/12/29 Javascript
如何使用gpu.js改善JavaScript的性能
2020/12/01 Javascript
[01:12:40]DOTA2-DPC中国联赛 正赛 DLG vs XG BO3 第三场 1月25日
2021/03/11 DOTA
Python 除法小技巧
2008/09/06 Python
Python应用库大全总结
2018/05/30 Python
python如何爬取动态网站
2020/09/09 Python
python爬取微博评论的实例讲解
2021/01/15 Python
Adobe Html5 Extension开发初体验图文教程
2017/11/14 HTML / CSS
英国最大的女性服装零售商:Dorothy Perkins
2017/03/30 全球购物
MADE荷兰:提供原创设计师家具
2018/04/03 全球购物
德国汽车零件和汽车配件网上商店:kfzteile24
2018/11/14 全球购物
伦敦著名的运动鞋综合商店:Footpatrol
2019/03/25 全球购物
Roxy荷兰官方网站:冲浪、滑雪板、服装和配件
2019/10/22 全球购物
营销主管自我评价怎么写
2013/09/19 职场文书
财务人员个人求职信范文
2013/12/04 职场文书
文化建设工作方案
2014/05/12 职场文书
保险专业求职信
2014/07/07 职场文书
竞聘演讲稿怎么写
2014/08/28 职场文书