前端文件下载

前端文件下载

a 标签

通过 a 标签的 download 属性来实现文件下载
这种方式是最简单的,也是我们比较常用的方式

<a href="http://www.baidu.com" download="baidu.html">下载</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 的最后一部分作为文件名

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 是假想)

location.href

这种方式 和 window.open(url) 是一样的

location.href = "http://www.baidu.com";

拥有window.open的所有缺陷,所以不推荐使用

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 一样,这些方式的缺点都一样
同时还有属于每个属性自身的特性

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();
};

主要的逻辑是当我们的请求成功后,我们会拿到响应体的 response
这个 response 就是我们要下载的内容,然后我们把它转换成 blob 对象
然后通过 URL.createObjectURL 来创建一个 url
然后通过 a 标签的 download 属性来实现文件下载。

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

blob

来自 mdn
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,文件不会损毁,但是无法被正常识别

URL.createObjectURL

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 属性是写死的
如果在文件类型是确定的情况下是没问题的,但是如果这个接口就是下载文件的接口
文件可能是各种类型的,我们应该怎么处理?

没有正确答案
第一个 可以和接口提供者进行协商,协商方案是不确定的
第二个 通过 responseheader 来获取文件的 type

const type = response.headers["content-type"];
const blob = new Blob([response.data], { type });

通过 responseheader 来获取 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 });

总结

最终还是落到 a 标签上,所以不管是通过浏览器的内置行为进行下载
还是通过 ajax 进行下载,文件下载的最终还是浏览器的行为

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值