# 前端文件下载
简单总结下自己工作中用到过的几种文件下载的方式,以及有什么需要注意的地方
# 1、直接使用 a 标签(同源文件)
最简单的方式,适用于同源或服务器已设置 Content-Disposition: attachment 的文件。
<a href="./test.txt" download="test.txt">下载文件</a>
优点:简单、无需 JS。
缺点
- 跨域文件会被浏览器直接打开而非下载(除非服务器设置了
Content-Disposition: attachment)。 download属性在 IE 和旧版 Edge 中无效。
比如下面这种跨域的,可能会直接打开文件
<a href="https://xdyuan.cn/homelogo.jpg" target="_blank" download="logo.jpg">下载图片</a>
# 2、动态创建 a 标签(JS 控制)
通过 JS 动态生成 <a> 标签,适用于需要逻辑判断的场景。
function downloadFile(url, fileName) {
const a = document.createElement('a');
a.href = url;
a.download = fileName; // 设置下载文件名
a.style.display = 'none';
document.body.appendChild(a);
a.click();
document.body.removeChild(a);
}
// 示例:下载同源文件
downloadFile('./test.txt', 'test.txt');
# 3、请求后端数据然后下载
转为 Blob 对象后生成临时 URL 下载。适用于跨域文件(需 CORS 支持) 或前端生成文件的场景。
- 优点
- 支持跨域(需服务器设置
Access-Control-Allow-Origin)。 - 可处理动态生成的内容(如 JSON、Canvas 导出图片)。
- 支持跨域(需服务器设置
- 缺点
- 大文件占用内存(需后端分片或流式处理优化)。
- 无法获取真实文件名(需前端指定),或者后端通过content-disposition头指定文件名。
function downloadFile(url, fileName) {
const xhr = new XMLHttpRequest();
xhr.open('GET', url, true);
xhr.responseType = 'blob';
xhr.onload = function () {
if (xhr.status === 200) {
const blob = xhr.response;
const blobUrl = URL.createObjectURL(blob);
const a = document.createElement('a');
a.href = blobUrl;
a.download = fileName;
a.click();
URL.revokeObjectURL(blobUrl);
}
};
xhr.send();
}
根据响应头截取文件名
function getFileNameFromContentDisposition(disposition) {
if (!disposition) return '';
var filename = '';
disposition = decodeURIComponent(disposition);
/*
"filename" 和 "filename*" 两个参数的唯一区别在于,"filename*" 采用了 RFC 5987 中规定的编码方式。当 "filename" 和 "filename*" 同时出现的时候,应该优先采用 "filename*",假如二者都支持的话。
*/
if (disposition.indexOf('attachment') !== -1) {
var filenameRegex1 = /filename[^;=\n]*=((['"]).*?\2|[^;\n]*)/;
var filenameRegex2 = /filename\*?=([^']*'')?([^;]*)/;
var matches1 = filenameRegex1.exec(disposition);
var matches2 = filenameRegex2.exec(disposition);
if (matches2 !== null && matches2[2]) {
filename = matches2[2];
} else if (matches1 !== null && matches1[1]) {
filename = matches1[1];
}
if (filename) {
filename = filename.replace(/['"]/g, '');
}
}
return filename;
}
# 3.1 使用axios也是一样的逻辑,
只不过有时候blob需要自己生成
axios.get(url, { responseType: 'blob' })
.then(res => {
const blobUrl = URL.createObjectURL(new Blob([res.data]));
// 创建 a 标签下载...
});
# 4、导出文件的axios实例
下面是一个示例
/*
文件下载的axios
*/
import axios from 'axios';
const downloadAxios = axios.create({
baseURL: process.env.BASE_API || '',
timeout: 60000,
responseType: 'arraybuffer'
});
downloadAxios.interceptors.request.use(
config => {
const token = localStorage.get('token');
if (token) {
config.headers.Authorization = 'Bearer ' + token;
}
return config;
},
error => {
Promise.reject(error);
}
);
downloadAxios.interceptors.response.use(
response => {
if (response.status === 200) {
const disposition = response.headers['content-disposition'];
// console.log(disposition,'disposition')
let fileName = getFileNameFromContentDisposition(disposition);
let nameArr = fileName.match(/\"[\S\s]+\"/);
fileName = nameArr ? nameArr[0].replace(/\"/g, '') : '文件名';
const blob = new Blob([response.data]);
const url = URL.createObjectURL(blob);
const a = document.createElement('a');
a.download = fileName;
a.href = url;
a.setAttribute('download', `${fileName}`);
a.click();
URL.revokeObjectURL(url);
a.remove();
return url;
} else {
return false;
}
},
error => {
return Promise.reject(error);
}
);
export default downloadAxios;
用法
downloadAxios({
url: '/url/download',
method: 'GET',
params
});