0x1461A0

前端实现文件下载

浏览器打开链接后默认会尝试预览该文件,浏览器下载的本质是告诉浏览器将该资源提供给用户进行保存 两种情况浏览器会主动将一个链接对应的资源进行下载

  1. 响应Content-Dispositionattachment显示的告诉浏览器进行资源的下载
  2. 响应Content-Type为浏览器不支持预览的类型/缺少该字段但浏览器判断出该文件不支持预览

手动实现文件下载需要利用浏览器的这种行为(本质上就是打开文件的下载链接),可以有几种方式:

  • form表单提交
    • 一种古老的文件下载方式
    • 核心是当需要进行下载时动态生成一个表单,利用表单提交的功能来实现文件的下载
javascript
function downloadFile (url) { const form = document.createElement('form') form.action = url form.method = 'get' form.style.display = 'none' document.body.appendChild(form) form.submit(); // 提交表单,下载文件 document.body.removeChild(form) }
  • window.open/location.href
  • a链接跳转

这几种方式都可以让页面跳转到下载链接实现文件的下载,并且可以发现,如果是在当前 tab 页面跳转触发下载行为,地址栏不会改变 缺点这几种方式当然也一样:

  • 当跳转的下载链接缺少Content-Disposition时只能下载浏览器无法预览的文件类型,浏览器可预览的文件类型会跳转为预览
  • 无法携带多余的 HTTP header,在一些鉴权的场景无法使用

a 标签 download

HTML5 新增download属性可以让浏览器直接下载所有类型文件,无需依赖Content-Disposition

html
<a href="example.jpg" download>点击下载</a> <!-- 重命名下载文件 --> <a href="example.jpg" download="test">点击下载</a>

download仅对同源 URL 或blob:data:协议起作用

  • 对于跨域链接download会失效,浏览器依旧会优先进行文件的预览而不是下载
  • 如果非要进行跨域下载,可以先将数据转换为blob:data:再进行下载

blob 和 dataURL

对于blob:data:协议的下载

  1. 获取二进制数据并转化为Blob,使用URL.createObjectUrl生成地址 / 获取二进制数据并转化为 Data URL
  2. 借助a标签进行下载
javascript
function downloadFile(url, name) { const a = document.createElement('a') a.style.display = 'none' a.href = url a.download = name; document.body.appendChild(a) a.click() document.body.removeChild(a) } function fetchData() { return new Promise((resolve) => { const xhr = new XMLHttpRequest() xhr.open('get', path) xhr.responseType = 'blob' xhr.send() xhr.onload = function () { resolve(this.response) }; }) } // blob const response = await fetchData() const url = URL.createObjectURL(this.response) downloadFile(url, 'example.txt') URL.revokeObjectURL(url) // data url const response = await fetchData() const fileReader = new FileReader() fileReader.readAsDataURL(response) fileReader.onload = function () { downloadFile(this.result, 'example.txt') }

这两种方式存在的问题也都一样

  • 需要先将文件请求到本次才进行下载,具有两次下载
  • 大文件会占用大量内存,这可能导致性能问题,尤其是在移动设备或资源受限的环境中

优点是

  • 可以在客户端动态生成文件内容,不一定需要再服务器上生成或存储文件
  • 可以在需要鉴权的环境下进行文件的下载

Content-Disposition

Content-DispositionHTTP 响应头指示客户端以何种形式显示响应内容 基本的格式:

http
Content-Disposition: <disposition-type>; [filename=<filename>]

disposition-type表示处理方式

  • attachment: 告诉客户端应该将文件作为附件下载,如果后面存在 filename,会作为下载的文件名
  • inline: 指明直接展示资源,当然当浏览器不支持改类型的资源是依旧会提示下载
  • 其他自定义值: 可以是其他处理方式,具体效果取决于用户代理的支持情况

优先级 attachiment的优先级是最高的,无论使用何种方式跳转链接,都会实现文件下载。 当 disposition-type值为inline时,download 会优先于 inline实现文件下载 参考

AuthorPosted onUpdated on
0x1461A02023-11-282023-12-01

本文使用CC BY-NC-SA 4.0创作共享协议,转载请署名,图片请转存。

本文最后更新于 260 天前,文中所描述的信息可能已发生改变