前端文件下载

712 阅读6分钟

文件下载相关请求头和响应头

// 请求头
Accept: 指定客户端接受的内容类型,如 Accept: application/octet-stream 表示接受二进制流文件。
Range: 请求部分内容,例如 Range: bytes=0-499 只请求文件的前500字节,适用于断点续传。
Accept-Encoding:指定客户端支持的内容编码方式,如压缩。例如:Accept-Encoding: gzip, deflate。
User-Agent:提供客户端软件的信息,通常用来识别浏览器类型。例如:User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.110 Safari/537.36.
Referer:表示请求的来源页面。对于文件下载来说,可能会用来防止直接下载链接的滥用。例如:Referer: https://example.com/download.
Authorization:用于在下载文件时携带身份验证信息,如基于 BearerToken。例如:Authorization: Bearer <token>。

// 响应头
Content-Disposition: 告诉浏览器应该如何处理响应体中的内容,通常用来触发下载行为。例如: Content-Disposition: attachment; filename="example.pdf"
- inline:指示浏览器直接显示内容,通常用于显示图像、PDF 等可以在浏览器中渲染的文件。
- attachment:指示浏览器将文件作为附件下载,并且不在浏览器中直接显示。
Content-Type: 表示文件返回的媒体类型,如 Content-Type: application/pdf。
Content-Length: 文件的大小,以字节为单位。
Cache-Control:用于控制缓存行为。在文件下载的情况下,通常会使用以下设置:Cache-Control: no-cache, no-store, must-revalidate
- no-cache:指示浏览器不要缓存文件,每次下载时都从服务器获取最新的文件。
- private 或 no-store:防止文件被缓存或存储。
Expires:用于设置文件缓存的到期时间。通常与 Cache-Control 一起使用,用于指定缓存的有效期。对于下载文件,通常会设置为一个过去的时间来禁用缓存。
ETag:用于标识资源的唯一版本。当文件更新时,ETag 的值会变化,帮助浏览器判断文件是否发生了变化,从而决定是否重新下载文件。
Content-Range: 在分段下载时,显示响应的部分内容范围,例如 Content-Range: bytes 0-499/1234Accept-Ranges: 指示服务器支持断点续传,例如 Accept-Ranges: bytes。

一、location.href

对于一些浏览器无法识别的文件格式,可以直接再浏览器地址栏输入url即可触发浏览器的下载功能。对于单文件下载没有什么问题,但是如果下载多文件,点击过快就会重置掉前面的请求。

适用场景

  • get请求
  • 单文件下载
window.location.href = url;

1、文件类型pdf等,浏览器直接输入链接即可下载,但有例外:

  • 浏览器配置,如谷歌浏览器,谷歌浏览器设置》隐私和安全》网站设置》PDF文档,可设置访问链接时下载/预览文件
  • 服务器的 【Content-Disposition】 头部决定了浏览器如何处理文件。假设希望文件在浏览器中打开,而不是下载,应该确保 【Content-Disposition】 头部设置为 【inline】,而不是 【attachment】:
`inline`:告诉浏览器在页面中直接显示 PDF 文件。
`attachment`:告诉浏览器下载文件,而不是直接显示。

Content-Disposition: inline; filename="document.pdf"

2、图片类型jpg等,浏览器直接输入链接,只能预览

3、其他网页网址,当前窗口跳转新页面

// pdf下载,当前页下载文件(取决于浏览器配置和服务器配置)
window.open("https://www.w3.org/WAI/ER/tests/xhtml/testfiles/resources/pdf/dummy.pdf")

// 图片预览,当前窗口预览
window.open("https://picsum.photos/200/300")

// 其他网页网址,当前窗口跳转新页面
window.open("https://www.runoob.com/jsref/met-win-open.html")

二、window.open

和location.href类似

window.open(url);
  1. pdf等文件类型,直接下载,不会打开新窗口
  2. 图片类型,打开新窗口预览
  3. 其他网页网址,打开新窗口跳转页面
// pdf下载,当前页下载文件
window.open("https://www.w3.org/WAI/ER/tests/xhtml/testfiles/resources/pdf/dummy.pdf")

// 图片预览,打开新窗口预览
window.open("https://picsum.photos/200/300")

// 其他网页网址,打开新窗口跳转页面
window.open("https://www.runoob.com/jsref/met-win-open.html")

三、a标签

与上面两种类型类似,图片类型会被直接预览,文件类型等根据浏览器/服务器配置预览或者下载,但a标签有个download属性可触发文件下载以及设置下载的文件名,但该属性只在文件与页面来源相同的情况下有效。

适用场景

  • get请求
  • 单文件下载
  • 需要自定义文件名

a标签下载相关属性

download:
1、 当设置了 `download` 属性时,点击链接将触发文件下载,而不是直接在浏览器中打开文件。
2、你可以为下载的文件指定一个文件名。如果没有指定文件名,则会使用目标资源的默认文件名。

// 点击链接将触发文件下载,而不是直接在浏览器中打开文件
<a href="https://www.w3.org/WAI/ER/tests/xhtml/testfiles/resources/pdf/dummy.pdf" download>Download PDF</a>

// 指定文件名
<a href="https://www.w3.org/WAI/ER/tests/xhtml/testfiles/resources/pdf/dummy.pdf" download="被修改过的文件名">Download as New Name</a>

// 注意:
// 1、download 属性仅适用于同源的 URL,或者文件与页面来源相同的情况。跨域资源默认无法使用 download 属性,除非设置了相关的 CORS(跨源资源共享)策略。
// 2、该属性并不适用于所有文件类型,某些类型的文件可能仍然会在浏览器中打开(例如图片或文本文件)。

四、Blob对象(结合URL.createObjectURL和URL.revokeObjectURL实现文件下载)

1、Blob

  • Blob 对象表示一个不可变、原始数据的类文件对象
  • Blob 的数据可以按文本二进制的格式进行读取,也可以转换成ReadableStream来用于数据操作。
  • 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'' })

2、URL.createObjectURL

URL.createObjectURL() 是一个 JavaScript 方法,它用于创建一个指向 Blob 或 File 对象的 URL。这个方法非常适用于处理文件上传、图像预览、视频播放等场景。通过这个 URL,你可以在浏览器中访问本地文件或生成的 Blob 数据,而无需将其上传到服务器。

let objectURL = URL.createObjectURL(blob);

3、URL.revokeObjectURL

URL.revokeObjectURL() 是一个在 Web API 中提供的函数,用于释放先前通过 URL.createObjectURL() 创建的对象 URL。当不再需要这个 URL 时调用 revokeObjectURL() 是非常重要的,以便释放浏览器的资源,防止内存泄漏。

URL.revokeObjectURL(objectURL);

4、下载实现

(1)将后端返回的blob类型数据,通过URL.createObjectURL(blob)转化为url;

(2)生成a标签dom元素,把url赋值到href属性,手动触发a标签点击事件下载文件;

(3)移除a标签dom元素,通过URL.revokeObjectURL(url)释放资源;

      const xhr = new XMLHttpRequest();
      xhr.open("get", "https://httpbin.org/bytes/1000");
      xhr.responseType = "blob";
      xhr.send();
      xhr.onload = function () {
        if (this.status === 200 || this.status === 304) {
          const url = URL.createObjectURL(this.response);
          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);
          URL.revokeObjectURL(url);
        }
      };

五、form表单

通过form表单来实现文件下载,可以通过创建和添加其他表单元素(例如隐藏的input元素),以便传递数据或参数。

    downloadFile() {
      // 创建一个form元素
      const form = document.createElement('form');
      form.method = 'GET';
      form.action = 'http://example.com/file.pdf';

      // 创建一个隐藏的input元素用于传递参数(可选)
      const input = document.createElement('input');
      input.type = 'hidden';
      input.name = 'param1';
      input.value = 'value1';
      form.appendChild(input);

      // 将form元素添加到页面中
      document.body.appendChild(form);

      // 提交表单进行文件下载
      form.submit();

      // 移除动态创建的form元素
      document.body.removeChild(form);
    }