阅读 1806

前端如何通过a链接下载文件

文件下载是很多项目中的常见需求,实现方式通常是使用 a 标签实现:

<a href="123.jpg">下载</a>复制代码

但是在实际使用中发现,点击该链接后并不是下载对应的文件,而是在浏览器中打开了该文件,这是为什么呢?当服务器向浏览器发送文件时,如果是浏览器支持的文件类型,一般会默认使用浏览器打开,比如 txt、jpg、pdf 等。如果需要将文件下载保存在本地,则需要使用 HTTP 响应头 Content-Disposition 进行处理。

Content-Disposition 实现文件下载

在服务端设置 Content-Disposition,其属性设置为 attachment; filename='123.jpg',其中 attchment 表示以附件的形式下载并保存到本地;filename 为下载后的文件名。

// Midway.js 中设置响应头

this.ctx.set({
  "Content-Type": "image/jpeg",
  "Cache-Control": "no-cache",
  "Content-Disposition": "attachment; filename=123.jpeg"
});复制代码

Content-Disposition 的实现方式需要服务端配合,那么有没有其它的方式,在客户端即可实现文件的下载呢?其中的一种实现方式是使用 a 标签的 download 属性。

download 属性实现文件下载

在 a 标签中添加 download 属性:

<a href="123.jpg" download>下载</a>复制代码

这样就可以直接调用浏览器的下载功能,而且还可以给download属性设置值来规定下载文件的名称,如果在设置值时没有指定文件的扩展名,浏览器将自动检测正确的文件名并添加到文件(.jpg, .pdf, .txt, .html, 等等)。

<a href="123.jpg" download='othername.jpg'>下载</a>复制代码

download 是 HTML5 中新增的属性,因此必定会存在兼容性的问题:

然而,caniuse 展示的兼容性只是一个笼统,download 表现最为直观的一个问题就是跨域的问题。如果是加载了非同源的内容,该属性将会失效,等效于导航功能。

如果需要下载的资源是跨域的,包括跨子域,在Chrome浏览器下,使用download属性是可以下载的,但是,并不能重置下载的文件的命名;而FireFox浏览器下,则download属性是无效的,也就是FireFox浏览器无论如何都不支持跨域资源的download属性下载。

如果资源是同域名的,则两个浏览器都是畅通无阻的下载,不会出现下载变浏览的情况。

download 属性有兼容性问题,因此这并不是一个完美的解决方案,那么在客户端还有没有其它的方式实现文件的下载呢?

当然是有的,我们可以使用 URL.createObjectURL() 创建一个非跨域的数据源。

URL.createObjectURL() 实现文件下载

首先,下载源数据文件,生成blob对象,这里使用 fetch 进行下载:

function downloadFile(url: string, filename?: string) {
  fetch(url, {
    headers: new Headers({
      Origin: location.origin,
    }),
    mode: 'cors',
  })
    .then(res => {
  		if( res.status == 200 ) {
      	// 返回的.blob()为promise,然后生成了blob对象,此方法获得的blob对象包含了数据类型,十分方便
     		return res.blob()
      }
          
      throw new Error(`status: ${response.status}.`)

  	})
    .then(blob => {
      download(blob, filename)
    })
}复制代码

然后,通过 URL.createObjectURL 给 a 标签设置数据源:

function download(blob: Blob, filename?: string) {
  const a: any = document.createElement('a')
  a.download = filename
  const blobUrl = URL.createObjectURL(blob)
  a.href = blobUrl
  document.body.appendChild(a)
  a.click()
  a.remove()
  URL.revokeObjectURL(blobUrl)
}复制代码

这样就可以实现在跨域的情况下通过a标签下载资源了。

在本文中,介绍了三种通过a链接下载文件的方案,我们可以根据实际的业务场景,选用其中的一种方案。


作者:紫圣
链接:https://juejin.cn/post/7039109468080062500


文章分类
前端
文章标签
版权声明:本站是系统测试站点,无实际运营。本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 XXXXXXo@163.com 举报,一经查实,本站将立刻删除。
相关推荐