关于html:前端文件下载的正确打开方式

5次阅读

共计 3614 个字符,预计需要花费 10 分钟才能阅读完成。

前端波及到的文件下载还是很多利用场景的,那么前端文件下载有多少种形式呢?每种形式有什么优缺点呢?上面就来一一介绍。

  1. a 标签
    通过 a 标签的 download 属性来实现文件下载,这种形式是最简略的,也是咱们比拟罕用的形式,先来看示例代码:

下载
就下面的这个示例,咱们点击下载,发现是跳转到了百度的首页,并没有真的下载文件。

因为 a 标签下载只能下载同源的文件,如果是跨域的文件,这里包含图片、音视频等媒体文件,都是预览,也无奈下载。

下面的代码是间接通过书写 a 标签来实现文件下载,咱们也能够通过 js 来实现,代码如下:

const a = document.createElement(‘a’)
a.href = ‘http://www.baidu.com’
a.download = ‘baidu.html’
a.click()
成果和下面的一样,都是跳转到百度的首页,没有下载文件。

这里的重点是 a 标签的 download 属性,这个属性是 HTML5 新增的。

它的作用是指定下载的文件名,如果不指定,那么下载的文件名就会依据申请内容的 Content-Disposition 来确定,如果没有 Content-Disposition,那么就会应用申请的 URL 的最初一部分作为文件名。

  1. window.open
    下面应用 a 标签的案例也能够通过 window.open 来实现,成果是一样的,代码如下:

window.open(‘http://www.baidu.com’, ‘_blank’)
这里的_blank 是指定关上的形式,如果不指定,那么就会在以后页面关上,这里指定_blank,就是在新的页面关上。

同样 a 标签的 download 属性也是能够应用的,代码如下:

window.open(‘http://www.baidu.com’, ‘_blank’, ‘download=baidu.html’)
当然这种形式也是有缺点的,比照于 a 标签,这种形式不能下载.html、.htm、.xml、.xhtml 等文件,因为这些文件会被当成 html 文件来解决,所以会间接在以后页面关上。

同样也不能下载跨域的文件,毕竟是 window.open,不是 window.download(window.download 是假想)。

  1. location.href
    这种形式和 window.open(url)是一样的,代码如下:

location.href = ‘http://www.baidu.com’
这种形式领有 window.open 的所有缺点,所以不举荐应用,这里只当作理解,所以不做过多的解说。

  1. location.? 其余属性
    这里的其余指代的都是能跳转页面的属性,比方 location.assign、location.replace、location.reload 等,这些属性都是能够实现文件下载的,代码如下:

location.assign(‘http://www.baidu.com’)
location.replace(‘http://www.baidu.com’)
location.reload(‘http://www.baidu.com’)
这里的 location.reload 是有点非凡的,它的作用是从新加载以后页面,然而它也能够承受一个参数,这个参数就是要跳转的页面,所以也能够实现文件下载。

当然同 location.href 一样,这些形式的毛病都一样,同时还有属于每个属性本身的个性,这里只当拓展常识,不做过多的解说。

  1. XMLHttpRequest
    这种形式就是咱们常说的 ajax 下载,包含 axios、fetch 等都是雷同的,代码如下:

const xhr = new XMLHttpRequest()
xhr.open(‘GET’, ‘http://www.baidu.com’)
xhr.send()

xhr.onload = function () {
const blob = new Blob([xhr.response], {type: ‘text/html’})
const a = document.createElement(‘a’)
a.href = URL.createObjectURL(blob)
a.download = ‘baidu.html’
a.click()
}
这里就不讲和 XMLHttpRequest 相干的常识了,只讲和文件下载相干的局部。

这里次要的逻辑是当咱们的申请胜利后,咱们会拿到响应体的 response,这个 response 就是咱们要下载的内容,而后咱们把它转换成 blob 对象,而后通过 URL.createObjectURL 来创立一个 url,而后通过 a 标签的 download 属性来实现文件下载。

这里的知识点就有两个,一个是 blob 对象,一个是 URL.createObjectURL。

5.1 blob
上面是 blob 对象的定义,来自 MDN[1]:

Blob 对象示意一个不可变、原始数据的类文件对象。它的数据能够按文本或二进制的格局进行读取,也能够转换成 ReadableStream 来用于数据操作。

Blob 示意的不肯定是 JavaScript 原生格局的数据。File 接口基于 Blob,继承了 blob 的性能并将其扩大以反对用户零碎上的文件。

blob 对象是 html5 新增的对象,它的作用是用来存储二进制数据的,比方图片、视频、音频等,它的应用办法如下:

/**

  • @param {Array} array 二进制数据
  • @param {Object} options 配置项
  • @param {String} options.type 文件类型,它代表了将会被放入到 blob 中的数组内容的 MIME 类型。
  • @param {String} options.endings 用于指定蕴含行结束符 \n 的字符串如何被写入。默认为 transparent,示意不会批改行结束符。还能够指定为 native,示意会将 \n 转换为 \r\n。
    */

const blob = new Blob([], { type: ”})
这里次要关注的是 type 属性,默认状况下,blob 对象是没有 type 属性的,那么这个 Blob 就是一个无类型的 Blob,文件不会损毁,然而无奈被失常辨认。

5.2 URL.createObjectURL
上面来自 MDN[2]:

URL.createObjectURL() 静态方法会创立一个 DOMString,其中蕴含一个示意参数中给出的对象的 URL。这个 URL 的生命周期和创立它的窗口中的 document 绑定。这个新的 URL 对象示意指定的 File 对象或 Blob 对象。

这个办法是用来创立一个 url 的,它的作用是把一个 blob 对象转换成一个 url,这个 url 能够用来下载文件,也能够用来预览文件,代码如下:

const url = URL.createObjectURL(blob)
这里须要留神的是,这个 url 的生命周期和创立它的窗口中的 document 绑定,也就是说,当咱们的 document 被销毁后,这个 url 就会生效,所以咱们须要在适合的机会销毁它,代码如下:

URL.revokeObjectURL(url)
回到咱们方才下载的问题,咱们是通过 blob 对象来解决,然而咱们的 type 属性是写死的,如果在文件类型是确定的状况下是没问题的,然而如果这个接口就是下载文件的接口,文件可能是各种类型的,咱们应该怎么解决?

这里的没有正确答案,第一个能够和接口提供者进行协商,协商计划是不确定的,第二就是通过 response 的 header 来获取文件的 type,也是咱们要讲的:

const type = response.headers[‘content-type’]

const blob = new Blob([response.data], {type})
这里咱们通过 response 的 header 来获取 type,而后再创立 blob 对象,这样就能够正确的下载文件了。

其实 content-type 也可能是 application/octet-stream,这个时候咱们就须要通过 file-type 来获取文件的 type 了。

上面的代码是通过 file-type 来获取文件的 type:

import {fileTypeFromStream} from ‘file-type’;

const type = await fileTypeFromStream(response.body);
const blob = new Blob([response.data], {type})
file-type 的应用能够参考这里[3]。

  1. 总结
    下面的计划这么多,其实最终还是落到 a 标签上,所以不论是通过浏览器的内置行为进行下载,还是通过 ajax 进行下载,文件下载的最终还是浏览器的行为。

参考资料
[1]
MDN: https://developer.mozilla.org…

[2]
MDN: https://developer.mozilla.org…

[3]
这里: https://github.com/sindresorh…

正文完
 0