通过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 相关文章推荐
同一个表单 根据要求递交到不同页面的实现方法小结
Aug 05 Javascript
Jquery中LigerUi的弹出编辑框(实现方法)
Jul 09 Javascript
javascript去除字符串中所有标点符号和提取纯文本的正则
Jun 07 Javascript
js实现带有介绍的Select列表菜单实例
Aug 18 Javascript
高效利用Angular中内置服务$http、$location等
Mar 22 Javascript
Bootstrap carousel轮转图的使用实例详解
May 17 Javascript
JS实现的缓冲运动效果示例
Apr 30 Javascript
jQuery实现模糊查询的方法分析
May 10 jQuery
vue 录制视频并压缩视频文件的方法
Jul 27 Javascript
对angularJs中2种自定义服务的实例讲解
Sep 30 Javascript
jQuery事件委托代码实践详解
Jun 21 jQuery
JavaScript交换变量的常用方法小结【4种方法】
May 07 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 事件机制(2)
2011/03/23 PHP
判断Keep-Alive模式的HTTP请求的结束的实现代码
2011/08/06 PHP
php多维数组去掉重复值示例分享
2014/03/02 PHP
PHP实现表单提交数据的验证处理功能【防SQL注入和XSS攻击等】
2017/07/21 PHP
javascript学习之闭包分析
2010/12/02 Javascript
javascript对下拉列表框(select)的操作实例讲解
2013/11/29 Javascript
JavaScript AOP编程实例
2015/06/16 Javascript
PHP结合jQuery实现的评论顶、踩功能
2015/07/22 Javascript
Ajax的概述与实现过程
2016/11/18 Javascript
canvas学习之API整理笔记(一)
2016/12/29 Javascript
js return返回多个值,通过对象的属性访问方法
2017/02/21 Javascript
微信小程序上滑加载下拉刷新(onscrollLower)分批加载数据(二)
2017/05/11 Javascript
vue踩坑记录之数组定义和赋值问题
2019/03/20 Javascript
利用weixin-java-miniapp生成小程序码并直接返回图片文件流的方法
2019/03/29 Javascript
Vue中Table组件行内右键菜单实现方法(基于 vue + AntDesign)
2019/11/21 Javascript
JavaScript实现PC端四格密码输入框功能
2020/02/19 Javascript
ES6使用 Array.includes 处理多重条件用法实例分析
2020/03/02 Javascript
javascript设计模式 ? 建造者模式原理与应用实例分析
2020/04/10 Javascript
使用python实现strcmp函数功能示例
2014/03/25 Python
Django forms组件的使用教程
2018/10/08 Python
对python requests发送json格式数据的实例详解
2018/12/19 Python
Python制作动态字符图的实例
2019/01/27 Python
使用python检查yaml配置文件是否符合要求
2020/04/09 Python
python爬虫使用正则爬取网站的实现
2020/08/03 Python
Python 利用Entrez库筛选下载PubMed文献摘要的示例
2020/11/24 Python
ghd官网:英国ghd直发器品牌
2018/05/04 全球购物
Pandora西班牙官方商店:PandoraShop.es
2020/10/05 全球购物
如何转换一个字符串到enum值
2014/04/12 面试题
党委书记岗位职责
2013/11/24 职场文书
求职信范文英文版
2014/01/05 职场文书
高一数学教学反思
2014/02/07 职场文书
质检部经理岗位职责
2014/02/19 职场文书
低碳生活的宣传标语
2014/06/23 职场文书
先进班组事迹材料
2014/12/25 职场文书
检讨书范文2000字
2015/01/28 职场文书
前台接待岗位职责范本
2015/04/03 职场文书