前端文件下载

1.最简单直接的方式

没有下载进度、不能鉴权、浏览器支持预览的不提供下载、url长度问题
window.open('file')
window.location.href = 'file'

2.a标签的download

(浏览器兼容性良好、不支持跨域、不能鉴权)
<a href="example.jpg" download>点击下载</a>

带上属性值,重命名下载文件名

<a href="example.jpg" download="test">点击下载</a>

检测是否支持download

const isSupport = 'download' in document.createElement('a');

3.Blob对象下载

它除了能利用已知文件地址路径进行下载外,还能通过发送ajax请求api获取文件流进行下载
/**
* 下载文件
* @param {String} path - 下载地址/下载请求地址。
* @param {String} name - 下载文件的名字/重命名(考虑到兼容性问题,最好加上后缀名)
*/
downloadFile (path, name) {
const xhr = new XMLHttpRequest();
xhr.open('get', path);
xhr.responseType = 'blob';
xhr.send();
xhr.onload = function () {
if (this.status === 200 || this.status === 304) {
// 如果是IE10及以上,不支持download属性,采用msSaveOrOpenBlob方法,但是IE10以下也不支持msSaveOrOpenBlob
if ('msSaveOrOpenBlob' in navigator) {
navigator.msSaveOrOpenBlob(this.response, name);
return;
}
// const blob = new Blob([this.response], { type: xhr.getResponseHeader('Content-Type') });
// const url = URL.createObjectURL(blob);
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);
}
};
}

该方法不能缺少a标签的download属性的设置。因为发请求时已设置返回数据类型为Blob类型(xhr.responseType = 'blob'),所以target.response就是一个Blob对象,打印出来会看到两个属性sizetype。虽然type属性已指定了文件的类型,但是为了稳妥起见,还是在download属性值里指定后缀名,如Firefox不指定下载下来的文件就会不识别类型。

如果发送请求时不设置xhr.responseType = 'blob',默认ajax请求会返回DOMString类型的数据,即字符串。这时就需要两处注释的代码了,对返回的文本转化为Blob对象,然后创建blob url,此时需要注释掉原本的const url = URL.createObjectURL(target.response)

4.Base64方式下载

/**
* 下载文件
* @param {String} path - 下载地址/下载请求地址。
* @param {String} name - 下载文件的名字(考虑到兼容性问题,最好加上后缀名)
*/
downloadFile (path, name) {
const xhr = new XMLHttpRequest();
xhr.open('get', path);
xhr.responseType = 'blob';
xhr.send();
xhr.onload = function () {
if (this.status === 200 || this.status === 304) {
const fileReader = new FileReader();
fileReader.readAsDataURL(this.response);
fileReader.onload = function () {
const a = document.createElement('a');
a.style.display = 'none';
a.href = this.result;
a.download = name;
document.body.appendChild(a);
a.click();
document.body.removeChild(a);
};
}
};
}

5.文件名相关

有可能是后端提供、前端获取文件名,header中Content-Disposition通常有两种形式**filename=*和filename=

提取文件名
// xhr是XMLHttpRequest对象
const content = xhr.getResponseHeader('content-disposition'); // 注意是全小写,自定义的header也是全小写
if (content) {
let name1 = content.match(/filename=(.*);/)[1]; // 获取filename的值
let name2 = content.match(/filename\*=(.*)/)[1]; // 获取filename*的值
name1 = decodeURIComponent(name1);
name2 = decodeURIComponent(name2.substring(6)); // 这个下标6就是UTF-8''
}
// 可能浏览器只支持UTF-8的

6.重命名文件

export const findType = ((name) => {
const index = name.lastIndexOf('.')
return name.substring(index+1);
})