通过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 相关文章推荐
网页里控制图片大小的相关代码
Jun 25 Javascript
jQuery 遍历json数组的实现代码
Sep 22 Javascript
js简单抽奖代码
Jan 16 Javascript
使用jquery制作弹出框效果
Apr 03 Javascript
修复jQuery tablesorter无法正确排序的bug(加千分位数字后)
Mar 30 Javascript
走进javascript——不起眼的基础,值和分号
Feb 24 Javascript
详解Vue2.0里过滤器容易踩到的坑
Jun 01 Javascript
浅谈webpack编译vue项目生成的代码探索
Dec 11 Javascript
微信小程序实现image组件图片自适应宽度比例显示的方法
Jan 16 Javascript
Vue+ElementUI实现表单动态渲染、可视化配置的方法
Mar 07 Javascript
在微信小程序中保存网络图片
Feb 12 Javascript
手动实现vue2.0的双向数据绑定原理详解
Feb 06 Vue.js
微信小程序登录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数组应用之比较两个时间的相减排序
2008/08/18 PHP
php使用正则过滤js脚本代码实例
2014/05/10 PHP
php的debug相关函数用法示例
2016/07/11 PHP
php自定义函数实现二维数组排序功能
2016/07/20 PHP
php中实现字符串翻转的方法
2017/02/22 PHP
PHP PDOStatement::rowCount讲解
2019/02/01 PHP
Swoole 5将移除自动添加Event::wait()特性详解
2019/07/10 PHP
js自定义事件及事件交互原理概述(一)
2013/02/01 Javascript
用javascript为页面添加天气显示实现思路及代码
2013/12/02 Javascript
Jquery左右滑动插件之实现超级炫酷动画效果附源码下载
2015/12/02 Javascript
jQueryUI中的datepicker使用方法详解
2016/05/25 Javascript
深入研究React中setState源码
2017/11/17 Javascript
使用Angular CLI生成 Angular 5项目教程详解
2018/03/18 Javascript
vue弹窗组件的实现示例代码
2018/09/10 Javascript
vsCode安装使用教程和插件安装方法
2020/08/24 Javascript
Vue $mount实战之实现消息弹窗组件
2019/04/22 Javascript
微信小程序自定义toast组件的方法详解【含动画】
2019/05/11 Javascript
React如何实现浏览器打印部分内容详析
2019/05/19 Javascript
继承行为在 ES5 与 ES6 中的区别详解
2019/12/24 Javascript
JavaScript实现简易聊天对话框(加滚动条)
2020/02/10 Javascript
Javascript实现html转pdf高清版(提高分辨率)
2020/02/19 Javascript
Vue+Element自定义纵向表格表头教程
2020/10/26 Javascript
[08:04]TI4西雅图DOTA2前线报道 海涛探访各路人马
2014/07/09 DOTA
[01:01:52]DOTA2-DPC中国联赛正赛 iG vs LBZS BO3 第一场 3月4日
2021/03/11 DOTA
Python解决抛小球问题 求小球下落经历的距离之和示例
2018/02/01 Python
python更改已存在excel文件的方法
2018/05/03 Python
PyQt5根据控件Id获取控件对象的方法
2019/06/25 Python
Mac 使用python3的matplot画图不显示的解决
2019/11/23 Python
html5实现输入框fixed定位在屏幕最底部兼容性
2020/07/03 HTML / CSS
阳光体育活动方案
2014/02/16 职场文书
小学生优秀评语大全
2014/04/22 职场文书
工作建议书范文
2014/05/13 职场文书
幼儿教师2014年度工作总结
2014/12/16 职场文书
高效课堂教学反思
2016/02/24 职场文书
详解Nginx启动失败的几种错误处理
2021/04/01 Servers
golang实现浏览器导出excel文件功能
2022/03/25 Golang