网页中下载文件的相关总结

0. 概述

文件下载是web应用中很常见的场景,在浏览器中下载文件, 最基本的方式就是——在页面内隐藏iframe, 而后将文件下载地址加载到iframe中, 从而触发浏览器的下载行为。 此外, html5引入a标签的download属性, 也是一种下载方式。html

<iframe src='download_url'></iframe>
<a download href='download_url'>下载</a>

下面针对下载地址的Response Header、浏览器兼容性, 以及一些特殊case, 作一些说明。html5

1. 怎样的文件url才能触发浏览器的下载行为?

能触发浏览器下载的url有两类:web

  • response header中指定了Content-Dispositionattachment,它表示让浏览器把响应体做为附件下载到本地 (通常Content-Disposition还会指定filename, 下载的文件默认就是filename指定的名字)chrome

  • response header中指定了Content-Typeapplication/octet-stream(无类型) 或者 application/zip(下载zip包时)以及其它几个不常见类型 (其中还有浏览器差别),其中 application/octet-stream表示http response为二进制流(没指定明确的type), 须要下载到本地, 由系统决定或者用户手动指定打开方式。shell

关于application/octet-stream的状况, 补充几点canvas

  • 这种response, 因为没有明确的type, 若是做为文件下载的话, 下载下来的文件将没有文件名和拓展名(文件名直接取的url path的最后一坨)跨域

  • 若是不做为文件下载, 好比已知response body是一张图片, 能够经过img标签来显示图片浏览器

  • 下载下来的内容, 只是缺乏文件拓展名而已, 文件内容是完整的, 若是知道它实际的拓展名, 手动改了就能经过系统默认的程序打开, 不改拓展名的话也能经过指定应用程序的方式打开app

关于response header的Content-Type, 补充几点curl

  • 首先要明确, Content-Type只是HTTP协议的部分, 不影响response body自身

  • Content-Type影响的是response的接收方(通常是浏览器), 对于浏览器而言, 它影响的是浏览器对响应体的处理方式. 好比指定为application/zip, 浏览器就会用pdf阅读器打开.

  • Content-Type之于浏览器, 就比如文件扩展名之于操做系统, 影响的默认行为, 若是你指定了打开方式, 那么Content-Type就不起做用了. 好比, 你在服务端对图片地址设置Content-Type为application/zip,但你在浏览器使用img标签(至关于指定了打开方式)去加载, 照样能正常加载图片。

为何上面说的「Content-Type」还有「文件拓展名」对于文件自身没有影响?
这里涉及到「文件格式协议」/「文件头」等内容, 待补充...

2. <iframe src='' > 下载方式

只要知足上述「触发浏览器自动下载」的url, 就能经过iframe的形式.
通常的用法是在html中隐藏iframe, 而后在业务代码中经过设置iframe的src来实现下载.

3. <a href='' download>下载方式

download兼容性

主流浏览器对于的特殊状况说明:

  • Safari只支持「能触发浏览器下载」的url

  • Firefox也只支持「能触发浏览器下载」的url, 此外还有一个须要注意的地方——点击a标签时, 会触发「浏览器离开当前页面」的行为, 解决这个问题的方式是「再搭配一个iframe, 将a标签的target指向这个iframe」,这样就不会有页面跳转了

  • Chrome对于「不能触发浏览器下载」的url, 也能够经过这种方式下载。

4. 用哪一种方式

对于下载来源彻底由本身控制的业务场景(意味着Response Header是统一的), 推荐<iframe>的方式。

  • 浏览器兼容性好

  • 若是跟「下载」操做一块儿还有一系列操做按钮, 能够统一代码结构. (否则的话就「下载」操做按钮是用的a标签, 其它按钮不是)

对于下载来源不受控制的场景, 则可选择<a download>的方式

  • 在chrome下, 比iframe方式兼容的下载场景多

番外. 无可奈何, 花式的下载方式

构想这样的场景, 对于Response Header中Content-Type为image/png的图片url,能怎样下载呢?(这里不考虑‘右键另存为’)

对于Chrome浏览器,使用<a download>的方式能够下载, 但其余浏览器怎么办呢?

若是要强行下载这张图片的话, 想了下, 也是有办法的

  • 代码中构造xhr请求该图片地址, 以Blob的形式接收Response, 而后转换成DataURL, 将DataURL的头部设置为image/octet-stream, 而后就可经过以上<iframe>的形式下载该DataURL了

  • 上面构造xhr请求的方式存在CORS问题, 若是不知足跨域条件, 简单点的替换方案是使用img标签加载图片,而后画到canvas上, 而后导出为DataURL, 后续同上...

一些备注

  • 下载文件时, 在浏览器devTools的Network面板没法查看下载请求的http相关信息, 若是你想观察上面提到的Response Header中相关的信息, 可经过shell指令curl对下载地址发送HEAD请求, 以查看Response Header.

  • 关于各类case的验证, 可本身简单写一个http服务, 设置不一样的Response Header, 而后打开浏览器验证。

  • 对于经过xhr去下载文件时跨域的问题, 有一个解决思路是, 本身写一个代理服务, 代理服务负责在服务端下载文件, 并配置好跨域相关的信息, 而后xhr请求走代理服务进行下载。

相关文章
相关标签/搜索