浅析HTML5中的download属性使用

  发布时间£º2019-03-13 14:48:29   作者£ºwanonder   我要评论

这篇文章主要介绍了浅析HTML5中的download属性使用£¬文中通过示例代码介绍的?#27973;?#35814;细£¬对大家的学习或者工作具有一定的参考学习价值£¬需要的朋友们下面随着小编来一起学习学习吧

随着前端技术的发展£¬越来越多的业务场景中需要前端来处理文件下载¡£在众多的方法中£¬通过 <a> 标签的 download 属性实现下载是其中常见也是比较简单的一种方法¡£

download 属性介绍

常规的 <a> 标签通过 href 实现链接跳转£¬如果只想下载文件而不是跳转预览£¬最好的方式是在 <a> 标签中添加 download 属性£¬就能很简单地实现下载操作¡£

download 是 HTML5 中 <a> 标签新增的一个属性£¬此属性会强制触发下载操作£¬指示浏览器下载 URL 而不是导航到它£¬并提示用户将其保存为本地文件£¬例如£º

<a href="result.png" download>download</a>

如果缺少 download 属性£¬点击 "download" 会直接变成预览?#35745;¬£?#24403;添加 download 属性后则会触发?#35745;?#30340;下载¡£

目前 download 属性的兼容性如caniuse 中所展示的£º

可以以看到£¬大部分主流的浏览器基本?#23478;?#32463;支持 download 属性£¬而 IE 的表现一如既往的感人£¬目前许多 Window 系统仍然在使用 IE £¬这也是许多业务需求需要考虑的¡£这种兼容性问题限制了 download 的更广泛应用¡£

动态资源下载

面对一些动态内容下载的业务场景£¬即?#35745;?#31561;资源的地址并不是固定的£¨例如一些在线绘图工具所生成的?#35745;¬£©£?#21482;使用 HTML 无法满足需求¡£为了能够满足不同的 URL 下载£¬可以通过JS 实现一个动态触发 URL 下载的方法¡£

function download(href, filename='')  {
  const a = document.createElement('a')
  a.download = filename
  a.href = href
  document.body.appendChild(a)  
  a.click()
  a.remove()
}

需要注意的是£¬代码中对创建的 <a> 进行的 appendChildremove 操作主要是为了兼容 FireFox 浏览器£¬在 FireFox 浏览器下调用该方法如果不将创建的 <a> 标签添加到 body 里£¬点击链?#30828;?#20250;有任何反应£¬无法触发下载£¬而在 Chrome 浏览器中则不受此影响¡£

上述的方法可以实现同源资源的下载¡£但在很多场景中£¬还需要处理跨域资源¡£遗憾的是£¬ download 属性目前仅适用于 同源 URL £¬即如果需要下载的资源地址是跨域的£¬ download 属性就会失效£¬点击链接会变成导航预览¡£

测试£º点击下载£¬结果只是预览而无法下载?#35745;¬¡?/p>

注£º Chrome65 之前是支持 download 属性触发文件跨域下载的£¬之后则?#32454;?#36981;循同源策略£¬无法再通过 download 属性触发跨域资源的下载¡£而 FireFox 一直不支持跨域资源的 download 属性下载¡£

文件命名问题

download 属性不仅可?#28304;?#21457;下载£¬也能指定下载文件名£º

<a href="test.png" download="joker.png">下载</a>

如果下载文件的后缀与源文件保持一致£¬可以设置缺省文件名£º

<a href="test.png" download="joker">下载</a>

笔者曾遇到过一个问题£¬通过 <a> 标签触发跨域资源下载£¬代码与上述的 download 方法基本相同£¬只是在设置 download 属性的地方有点不同£º

a.setAttribute(download, true)

结果在?#20064;?#26412;的 Chrome 浏览器中出现了如下情况¡£

下载文件名成了 true ¡£很明显£¬浏览器将 download 属性值读成了文件名¡£

经过分析£¬出现上述问题主要是因为£º

1. 首先本不?#23186;?download 设为 true £¬ downloaddisabled 这种类型的属性值不同£¬它与文件名直接相关联¡£而且对于这种前后端响应式下载的方式£¬ download 属性并不是必要的¡£

2. 在 Chrome 的早期版本不仅支持跨域资源的 download 属性下载£¬而?#19968;?#21487;以通过 download 重置跨域资源的文件名£¬因此才会出现上述这种情况¡£

前后端配合完成文件下载的业务场景£¬一般是由后端设置响应头中的 Content-Disposition 信息来实现¡£

在 HTTP 场景中£¬Content-Disposition 第一个参数或者是 inline£¨默认值£¬表示回复中的消息体会以页面的一部分或者整个页面的形式展示£©£¬或者是 attachment£¨意味着消息体应该被下载到本地£»大多数浏览器会呈现一个“保存为”的对话框£¬将 filename 的值预填为下载后的文件名£©¡£

如果在响应头中设置了 Content-Disposition £¬前端也在对应链接的 <a> 标签中添加了 download 属性£¬那么此时命名规则£º

如果 HTTP 头中的 Content-Disposition 属性赋予了一个不同于此属性的文件名£¬HTTP 头属性优先于此属性¡£

经过测试发现£¬当 HTTP 头中 Content-Disposition 不为空时£º

在 Chrome 浏览器中£¬不管 HTTP 头中 Content-Disposition 的第一个参数被设为 attachment 还是 inline £¬只要设置了 filename£¬ download 就无法重置文件名¡£相反£¬当 filename 为空时£¬ download 属性值会被设为文件名¡£ 在 FireFox 浏览器中£¬浏览器只会读取 Content-Disposition 的 filename 值£¬若是filename 为空£¬则取源文件名¡£此时 download 无论如何都无法重置文件名¡£

总结一下£º 未在响应头设置 Content-Disposition 信息£¨例如一般直接定位资源的同源URL£©£¬ download 属性可以重置文件名¡£若后端在 Content-Disposition 字段中已经设置了 filename£¬以 filename 值为准¡£

对于后端已经设定了文件名的情况下£¬如果仍然想要对文件名进行重置£¬该如何处理呢£¿

Blob: URL

关于 download 属性还有介绍£º

尽管 HTTP URL 需要位于同一源中£¬但是可以使用 blob: URL 和 data: URL £¬以方便用户下载使用 JavaScript 生成的内容£¨例如使用在线绘图 Web 应用程序创建的照片£©¡£

Blob £¨Binary Large Object£©即二进制大对象£¬这个我们并不?#21543;ú£?#19968;些数据库将Blob用来表示存储二进制文件的字段类型¡£File 接口也是基于 Blob£¬继承了 Blob 的功能并将其扩展使其支持用户系统上的文件¡£Blob 对象通过 Blob 构造函数来创建£º

Blob(blobParts[, options])

var debug = {hello: "world"};
var blob = new Blob([JSON.stringify(debug, null, 2)],
  {type : 'application/json'});

如果需要实现一些简单的文本或 JS 字符串之类的文件下载£¬可以通过将文本信息转成 blob 二进制流£¬生成一个 Blob URL£¬配合 download 属性完成下载£¬代码如下¡£

const downloadText = (text, filename = '') {
  const a = document.createElement('a')
  a.download = filename
  const blob = new Blob([text], {type: 'text/plain'})  
  // text指需要下载的文本或字符串内容
  a.href = window.URL.createObjectURL(blob) 
  // 会生成一个类似blob:http://localhost:8080/d3958f5c-0777-0845-9dcf-2cb28783acaf 这样的URL字符串
  document.body.appendChild(a)  
  a.click()
  a.remove()
}

这种 Blob URL 与常见的 HTTP URL 有什么区别呢£¿

Blob URL / Object URL是一种伪协议£¬可以让Blob和File对象用作图像?#25237;?#36827;制数据下载链接等URL源¡£

浏览器在内部通过 URL.createObjectURL() 创建一个对 Blob 或 File 对象的特殊引用£¬生成的 Blob URL 只能在浏览器本地的单个实例和同一会话中使用£¬并且这个 URL 对象会在页面退出的时候被浏览器?#22836;”Q?/p>

因此 Blob URL 并不能指向一个服务器资源 £¬你无法在其它页面中打开它¡£同时由于编码格式有所差别£¬Blob URL 比起 Data URLs 所占的空间资源更少£¬性能也更好¡£

Blob 为 Web 开发提供了一个?#27973;?#26377;用的功能£º创建 Blob URL¡£将二进制数据封装为 Blob 对象£¬然后使用 URL.createObjectURL() 生成 Blob URL£¬由于Blob URL本身就是一个同源URL£¬可以使用该 URL 配合 download 解决跨域资源的下载以及命名问题¡£

解决方案

通过 Blob 和 Fetch 可?#36234;?#20915;跨域和文件命名的问题£º使用 fetch 获取跨域资源返回一个blob 对象并生成一个 Blob URL£¬配合 <a> 标签的 download 属性触发下载£¬代码如下£º

function download(href, filename = '')  {
  const a = document.createElement('a')
  a.download = filename
  a.href = href
  document.body.appendChild(a)  
  a.click()
  a.remove()
}

function downloadFile(url, filename='') {
  fetch(url, {
    headers: new Headers({
      Origin: location.origin,
    }),
    mode: 'cors',
  })
    .then(res => res.blob())
    .then(blob => {
      const blobUrl = window.URL.createObjectURL(blob)
      download(blobUrl, filename)
      window.URL.revokeObjectURL(blobUrl)
    })
}

此时再点击下载£¬可以正常的将跨域?#35745;?#19979;载到本地了¡£

需注意的是跨域资源所在的服务器需要配置 Access-Control-Allow-Origin 信息£¬否则会得到一个大写的跨域报错¡£header 配置例如£º

// 允许任何域名访问
header('Access-Control-Allow-Origin: *');

//指定域名访问
header('Access-Control-Allow-Origin: https://h5.ele.me');

目前这种方法还存在一些不足£¬例如浏览器会限制 Blob 数据大小不超过500M£¬在性能方面也会有所不足¡£

总结

目前前端有很多种下载方法£¬ download 属性下载属于其中比较简单的一种£¬不过仔细考量其中的一些特性也能挖掘出很多有用的信息¡£ download 与浏览器特性紧密相关£¬目前该属性的兼容性也是一大问题£¬不过连微软官方都恳求用户不要再使用 IE £¬相信以后 download 的兼容性问题会?#20013;?#24471;到改善£¬应用前景也会越来越广阔¡£

以上就是本文的全部内容£¬希望对大家的学习有所帮助£¬也希望大家多多支持脚本之家¡£

相关文章

  • HTML5中的强制下载属性download使用实例解析

    链接中加入download属性可以使用户将文件下载下来而不是直接用浏览器打开,截止到目前为止对HTML5提供支持的浏览器已经对这个属性支?#20540;?#27604;较好了,下面我们就来详细看一下HTM
    2016-05-12
  • 详解HTML5中download属性的应用

    这篇文章主要介绍了HTML5中download属性的应用,文中对比了过去HTML版本中下载相关样式的写法以突出HTML5中改进后的优势,需要的朋友可以参考下
    2015-08-06
  • HTML5的download属性详细介绍和使用实例

    我一直在密切关注HTML5的最新革新£¬你会觉得我在浪费时间吗£¿HTML5给我们带来了很多¡°重型¡±的特征£¬例如WebSockets£¬Web Workers£¬History, Storage 和一些像 classList
    2014-04-23

最新评论

ÁÉÄþ35Ñ¡7¿ª½±½á¹û