通过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 window.event对象详尽解析
Feb 17 Javascript
javascript function、指针及内置对象
Feb 19 Javascript
使用JavaScript库还是自己写代码?
Jan 28 Javascript
JavaScript初学者应注意的七个细节详细介绍
Dec 27 Javascript
Knockout visible绑定使用方法
Nov 15 Javascript
jquery基础教程之deferred对象使用方法
Jan 22 Javascript
AngularJS 使用ng-repeat报错 [ngRepeat:dupes]
Jan 19 Javascript
JavaScript获取select中text值的方法
Feb 13 Javascript
基于JSONP原理解析(推荐)
Dec 04 Javascript
Vue.js上传图片到阿里云OSS存储的方法示例
Dec 13 Javascript
在vue项目中 实现定义全局变量 全局函数操作
Oct 26 Javascript
在antd中setFieldsValue和defaultVal的用法
Oct 29 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中用数组的方法设置cookies
2011/04/21 PHP
ThinkPHP独立分组使用的注意事项
2014/11/25 PHP
PHP使用in_array函数检查数组中是否存在某个值
2015/03/25 PHP
php实现scws中文分词搜索的方法
2015/12/25 PHP
jQuery移除元素自动解绑事件实现思路及代码
2014/05/31 Javascript
js+jquery实现图片裁剪功能
2015/01/02 Javascript
Javascript闭包实例详解
2015/11/29 Javascript
学习使用jquery iScroll.js移动端滚动条插件
2020/03/24 Javascript
jQuery实现的鼠标经过时变宽的效果(附demo源码)
2016/04/28 Javascript
基于Bootstrap+jQuery.validate实现表单验证
2016/05/30 Javascript
HTML5+Canvas调用手机拍照功能实现图片上传(上)
2017/04/21 Javascript
Vue.js中的图片引用路径的方式
2017/07/28 Javascript
Angular实现的进度条功能示例
2018/02/18 Javascript
微信小程序—setTimeOut定时器的问题及解决
2019/07/26 Javascript
[00:09]DOTA2新版本PA至宝特效动作展示
2014/11/19 DOTA
[00:35]DOTA2上海特级锦标赛 Newbee战队宣传片
2016/03/03 DOTA
Python列表推导式、字典推导式与集合推导式用法实例分析
2018/02/07 Python
Django 接收Post请求数据,并保存到数据库的实现方法
2019/07/12 Python
Django 过滤器汇总及自定义过滤器使用详解
2019/07/19 Python
Django模型修改及数据迁移实现解析
2019/08/01 Python
python爬虫 正则表达式解析
2019/09/28 Python
python自动化办公操作PPT的实现
2021/02/05 Python
浅谈CSS3鼠标移入图片动态提示效果(transform)
2017/11/06 HTML / CSS
canvas环形倒计时组件的示例代码
2018/06/14 HTML / CSS
AE美国鹰日本官方网站: American Eagle Outfitters
2016/12/10 全球购物
Smilodox官方运动服装店:从运动服到健身配件
2020/08/27 全球购物
运动会领导邀请函
2014/01/10 职场文书
简历自我评价模版
2014/01/31 职场文书
科研先进个人典型材料
2014/01/31 职场文书
质量月活动策划方案
2014/03/10 职场文书
班主任新年寄语
2014/04/04 职场文书
农村门前三包责任书
2014/07/25 职场文书
单位个人查摆问题及整改措施
2014/10/28 职场文书
街道党风廉政建设调研报告
2015/01/01 职场文书
2015年妇女工作总结
2015/05/14 职场文书
Java实现多线程聊天室
2021/06/26 Java/Android