如何用 JavaScript 下载文件
2018-01-08 14:34
316 查看
简介
我们知道,下载文件是一个非常常见的需求,但由于浏览器的安全策略的限制,我们通常只能通过一个额外的页面,访问某个文件的 url 来实现下载功能,但是这种用户体验非常不好。幸好,HTML 5 里面为
<a>标签添加了一个
download的属性,我们可以轻易的利用它来实现下载功能,再也不需要用以前的笨办法了。
原理
我们先看看 download的使用方法:
<a href="http://somehost/somefile.zip" download="filename.zip">Download file</a> |
<a>标签添加
download属性,我们点击这个链接的时候就会自动下载文件了~
顺便说下,
download的属性值是可选的,它用来指定下载文件的文件名。像上面的例子中,我们下载到本地的文件名就会是 filename.zip 拉,如果不指定的话,它就会是
somefile.zip 这个名字拉!
看到这里,你可能会说,坑爹啊,这明明是用 HTML 5 的新特性来实现下载文件嘛,说好的用 JavaScript 下载文件呢?
事实上,用 JavaScript 来下载文件也是利用这一特性来实现的,我们的 JavaScript 代码不外乎就是:
1.用 JavaScript 创建一个隐藏的
<a>标签
2.设置它的
href属性
3.设置它的
download属性
4.用 JavaScript 来触发这个它的
click事件
翻译成 JavaScript 代码就是:
var a = document.createElement('a');var url = window.URL.createObjectURL(blob);var filename = 'what-you-want.txt';a.href = url;a.download = filename;a.click();window.URL.revokeObjectURL(url); |
window.URL
window.URL里面有两个方法:
createObjectURL用
blob 对象来创建一个 object URL(它是一个
DOMString),我们可以用这个 object URL 来表示某个 blob 对象,这个 object
URL 可以用在
href和
src之类的属性上。
revokeObjectURL释放由
createObjectURL创建的
object URL,当该 object URL 不需要的时候,我们要主动调用这个方法来获取最佳性能和内存使用。
知道了这两个方法之后,我们再回去看看上面的例子就很容易理解了吧!只是用 blob 对象来创建一条 URL,然后让
<a>标签引用该 URL,然后触发个点击事件,就可以下载文件了!
那么问题来了,blob 对象哪里来?
Blob 对象
Blob 全称是 Binary large object,它表示一个类文件对象,可以用它来表示一个文件。根据 MDN 上面的说法,File API也是基于 blob 来实现的。
由于本文的主题是讲 JavaScript 下载文件,那我们构建 blob 的方式就是通过服务器返回的文件来创建 blob 拉!
而最简单的方式就是用
fetch API了,我们可以整合上面的例子:
fetch('http://somehost/somefile.zip').then(res => res.blob().then(blob => { var a = document.createElement('a'); var url = window.URL.createObjectURL(blob); var filename = 'myfile.zip'; a.href = url; a.download = filename; a.click(); window.URL.revokeObjectURL(url);})) |
你可能会问,何必这么麻烦呢?直接写成下面这样不就好了:
<a href="http://somehost/somefile.zip" download="myfile.zip">Download file</a> |
限制一:不同浏览器对 blob 对象有不同的限制
具体看看下面这个表格(出自 FileSaver.js):Browser | Constructs as | Filenames | Max Blob Size | Dependencies |
---|---|---|---|---|
Firefox 20+ | Blob | Yes | 800 MiB | None |
Firefox < 20 | data: URI | No | n/a | Blob.js |
Chrome | Blob | Yes | 500 MiB | None |
Chrome for Android | Blob | Yes | 500 MiB | None |
Edge | Blob | Yes | ? | None |
IE 10+ | Blob | Yes | 600 MiB | None |
Opera 15+ | Blob | Yes | 500 MiB | None |
Opera < 15 | data: URI | No | n/a | Blob.js |
Safari 6.1+* | Blob | No | ? | None |
Safari < 6 | data: URI | No | n/a | Blob.js |
限制二:构建完 blob 对象后才会转换成文件
这一点限制对小文件(几十kb)可能没什么影响,但对稍微大一点的文件影响就很大了。试想,用户要下载一个 100mb 的文件,如果他点击了下载按钮之后没看到下载提示的话,他肯定会继续按,等他按了几次之后还没看到下载提示时,他就会抱怨我们的网站,然后离开了。然而事实上下载的的确确发生了,只是要等到下载完文件之后才能构建 blob 对象,再转化成文件。而且,用户再触发多几次下载就会造成一些资源上的浪费。
因此,如果是要下载大文件的话,还是推荐直接创建一个
<a>标签拉~
写 html 也好,写 JavaScript 动态创建也好,用自己喜欢的方式去创建就好了。
为什么要用 JavaScript 下载文件
好拉,说了半天,其实我们一直说的都是:「不要用 JavaScript 下载文件拉,限制多多,又不好用,直接用 html 就好拉,简单方便又快捷」这个论调。事实上也确实如此,但有些时候我们确实需要通过 JavaScript 来做一些预处理。
权限校验
有些时候,我们需要对下载做一些限制,最常见的就是权限校验了,如检查该用户是否有下载的权限,是否有高速下载的权限等等。这时候,我们可以利用 JavaScript 做一些预处理。如:fetch('http://somehost/check-permission', options).then(res => { if (res.code === 0) { var a = document.createElement('a'); var url = res.data.url; var filename = 'myfile.zip'; a.href = url; a.download = filename; a.click(); } else { alert('You have no permission to download the file!'); }}); |
<a>标签的方式来实现下载,很简单吧!
动态文件
动态生成文件然后返回给客户端也是一个很常见的需求,譬如我们有时候需要做导出数据的功能,把数据库中的某些数据导出到 Excel 中,然后再返回客户端。这时候我们就不能简单的指定
href属性,因为对应的 URL 并不存在。
我们只能通过 JavaScript 对服务器发出一个请求,通知它去生成某个文件,然后把对应的 URL 返回给客户端。
有没有感觉这个过程和上面「权限校验」一节很像?肯定拉,因为我们只是对 URL 做了一些预处理而已嘛~
注意事项
由于 download属性是 HTML 5 的新特性,因此它不支持旧版本的浏览器。
总结
HTML 5 新的 download特性真的很好用,结合 JavaScript 的动态能力我们可以很方便的做出复杂的下载功能~
参考资料
https://github.com/eligrey/FileSaver.js/blob/master/FileSaver.jshttps://developer.mozilla.org/en-US/docs/Web/API/URL/createObjectURL
https://developer.mozilla.org/en-US/docs/Web/API/Blob
http://stackoverflow.com/questions/19327749/javascript-blob-filename-without-link
http://stackoverflow.com/questions/24501358/how-to-set-a-header-for-a-http-get-request-and-trigger-file-download
http://blog.bguiz.com/2014/07/03/file-download-with-http-request-header/
相关文章推荐
- js下如何弹出保存对话框进行文件下载
- 测试必备技能系列4:如何用SSH向linux服务器上传下载文件
- php大力力 [028节] 如何下载js文件,网上一个*.js无法下载啊??????
- php如何实现文件下载
- RoR网站如何利用lighttpd的X-sendfile功能提升文件下载性能
- 如何在FTP服务器上传和下载文件
- asp.net mvc + javascript生成下载文件
- 如何在ASP.NET中下载文件
- Android开发实践经验谈:如何让各式手机浏览器可以直接下载apk安装文件且实现自动安装APP
- 下载apk文件在/data/data/packagename/目录下,如何安装成功
- 如何实现window系统cmd环境下从远程FTP服务器上下载文件的方法
- 用idhttp打开网页或下载文件时如何显示进度
- 如何绕过wubi从网上下载镜像。(使用本地已存镜像文件而非再从网上下载)
- 如何用nfs命令烧写内核和文件系统(网络下载文件到nandflash)(未完)
- 如何处理:下载文件的按钮在事件未完成之前防止多次点击,事件完成之后又能继续点击提交
- 如何在Webstorm/Phpstorm中设置连接FTP,并快速进行文件比较,上传下载,同步等操作
- Delphi如何下载文件?
- 【转载】Java如何实现文件打包下载功能
- 如何在.net中实现文件下载
- SecureCRT如何用RZ,SZ传文件,上传和下载