文件导出的几种方式

1、返回文件流(二进制数据)

这是最常用的导出方式 ------ 后端实时生成文件(如 Excel、PDF),不落地存储,直接以二进制流形式返回给前端,前端接收后解析为可下载的文件。

js 复制代码
 
import axios from 'axios';

// 导出Excel接口请求
async function exportExcel() {
  try {
    const response = await axios({
      method: 'GET', // 也可用POST(传筛选参数时用POST)
      url: '/api/export/user-data', // 后端导出接口
      params: { status: 'active' }, // 筛选参数(可选)
      responseType: 'blob', // 关键:声明接收Blob二进制流
      headers: { 'Authorization': 'Bearer ' + token } // 权限头(可选)
    });

    // 1. 从响应头提取文件名(处理中文编码)
    const disposition = response.headers['content-disposition'];
    let filename = '默认文件名.xlsx';
    if (disposition) {
      // 匹配 filename*=UTF-8''xxx 格式(RFC 5987标准,支持中文)
      const match = disposition.match(/filename\*=UTF-8''([^;]+)/);
      if (match && match[1]) {
        filename = decodeURIComponent(match[1]); // 解码中文
      }
    }

    // 2. 转换Blob为下载URL
    const blob = new Blob([response.data], {
      // 手动指定MIME类型(与后端Content-Type一致,避免识别错误)
      type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'
    });
    const downloadUrl = URL.createObjectURL(blob);

    // 3. 创建<a>标签触发下载
    const a = document.createElement('a');
    a.href = downloadUrl;
    a.download = filename; // 文件名(浏览器会忽略URL中的文件名,以这个为准)
    document.body.appendChild(a);
    a.click(); // 模拟点击下载

    // 4. 清理资源(避免内存泄漏)
    document.body.removeChild(a);
    URL.revokeObjectURL(downloadUrl); // 销毁临时URL
  } catch (error) {
    console.error('导出失败:', error);
    // 特殊处理:若后端返回JSON错误(如参数错误),需解析Blob为JSON
    if (error.response?.data instanceof Blob) {
      const errorText = await new Response(error.response.data).text();
      alert('导出失败:' + JSON.parse(errorText).message);
    }
  }
}

2、 文件下载链接(URL)

后端先将文件生成并存储在服务器 / 云存储(如 OSS、S3),再返回一个 临时有效的下载链接(含签名 / 过期时间,保证安全),前端直接通过链接触发下载。

js 复制代码
async function getExportUrl() {
  try {
    const response = await axios.get('/api/export/get-download-url', {
      params: { status: 'active' } // 筛选参数
    });
    const { downloadUrl, filename } = response.data.data;

    // 方式1:用<a>标签下载(推荐,可指定文件名)
    const a = document.createElement('a');
    a.href = downloadUrl;
    a.download = filename; // 强制指定文件名(若链接含文件名也可省略)
    document.body.appendChild(a);
    a.click();
    document.body.removeChild(a);

    // 方式2:直接跳转(简单,但无法指定文件名,且可能触发浏览器预览)
    // window.location.href = downloadUrl;
  } catch (error) {
    console.error('获取下载链接失败:', error);
  }
}

//返回格式
 
{
  "code": 200,
  "message": "success",
  "data": {
    "downloadUrl": "https://xxx.com/files/export/user_123.xlsx?sign=abc123&expire=1717248000",
    "filename": "用户数据.xlsx",
    "expireTime": "2024-06-01 12:00:00"
  }
}
 

3、 后端返回「Base64 编码字符串」

后端将文件转换为 Base64 字符串(二进制→ASCII 字符),嵌入 JSON 返回给前端,前端解码后转换为文件。仅适合小文件(如 100KB 以内,Base64 会比原文件大 30%,大文件会导致请求体过大)。

js 复制代码
async function exportBase64File() {
  try {
    const response = await axios.get('/api/export/get-base64-file');
    const { base64Str, filename } = response.data.data;

    // 1. 解析Base64字符串(分离MIME类型和编码内容)
    const [meta, base64Data] = base64Str.split(',');
    const mime = meta.match(/:(.*?);/)[1]; // 提取MIME类型

    // 2. Base64解码为二进制数据(Uint8Array)
    const binaryStr = atob(base64Data); // atob解码Base64
    const len = binaryStr.length;
    const uint8Array = new Uint8Array(len);
    for (let i = 0; i < len; i++) {
      uint8Array[i] = binaryStr.charCodeAt(i); // 转换为二进制数组
    }

    // 3. 转换为Blob并下载(后续逻辑与文件流一致)
    const blob = new Blob([uint8Array], { type: mime });
    const downloadUrl = URL.createObjectURL(blob);

    const a = document.createElement('a');
    a.href = downloadUrl;
    a.download = filename;
    document.body.appendChild(a);
    a.click();

    // 清理资源
    document.body.removeChild(a);
    URL.revokeObjectURL(downloadUrl);
  } catch (error) {
    console.error('导出失败:', error);
  }
}

//返回格式 
{
  "code": 200,
  "message": "success",
  "data": {
    "base64Str": "data:application/vnd.openxmlformats-officedocument.spreadsheetml.sheet;base64,UEsDBBQABgAIAAAAIQ...",
    "filename": "用户数据.xlsx"
  }
} 
相关推荐
Mike_jia6 分钟前
NginxPulse:Nginx日志监控革命!实时洞察Web流量与安全态势的智能利器
前端
风之舞_yjf11 分钟前
Vue基础(31)_插件(plugins)、scoped样式
前端·vue.js
M ? A19 分钟前
Vue3+TS实战避坑指南
前端·vue.js·经验分享
Mintopia25 分钟前
你以为是技术问题,其实是流程问题:工程效率的真相
前端
Mintopia31 分钟前
一套能落地的"防 Bug"习惯:不用加班也能少出错
前端
亿元程序员33 分钟前
箭头游戏那么火,搞个3D的可以吗?我:这不是3年前的游戏了吗?
前端
IT_陈寒34 分钟前
SpringBoot里的这个坑差点让我加班到天亮
前端·人工智能·后端
巫山老妖38 分钟前
大模型工程三驾马车:Prompt Engineering、Context Engineering 与 Harness Engineering 深度解析
前端
Cobyte43 分钟前
4.响应式系统基础:从发布订阅模式的角度理解 Vue3 的数据响应式原理
前端·javascript·vue.js
晓得迷路了1 小时前
栗子前端技术周刊第 124 期 - ESLint v10.2.0、React Native 0.85、Node.js 25.9.0...
前端·javascript·eslint