# 前端文件下载

简单总结下自己工作中用到过的几种文件下载的方式,以及有什么需要注意的地方

# 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
});
上次更新: 1/29/2026, 9:17:42 AM