跳转至

这个问题在 若依(Vue3 + Axios)体系里是非常典型的,本质就是一句话:

后端返回的是 二进制流(stream) → 前端必须用 blob / arraybuffer 接收并手动处理

我给你按「实战级」讲清楚👇


一、前端怎么接收文件流(核心写法)

✅ 标准写法(若依推荐)

import request from "@/utils/request";

export function downloadFile(params) {
  return request({
    url: "/xxx/download",
    method: "get",
    params,
    responseType: "blob", // ⚠️ 关键
  });
}

👉 关键点:

  • responseType: 'blob':告诉 axios 这是二进制流
  • 返回值:resres.data 就是文件流

二、拿到流之后怎么处理

✅ 场景1:直接下载文件(最常见)

downloadFile().then((res) => {
  const blob = new Blob([res.data]);

  const url = window.URL.createObjectURL(blob);

  const link = document.createElement("a");
  link.href = url;

  // 文件名(推荐从后端拿)
  link.download = "文件.xlsx";

  document.body.appendChild(link);
  link.click();

  document.body.removeChild(link);
  window.URL.revokeObjectURL(url);
});

👉 原理:


✅ 场景2:预览(图片 / PDF)

const blob = new Blob([res.data]);
const url = URL.createObjectURL(blob);

this.previewUrl = url;

用法:

<img :src="previewUrl" />
<!-- 或 -->
<iframe :src="previewUrl"></iframe>

✅ 场景3:转 base64(小程序/特殊需求)

const reader = new FileReader();
reader.readAsDataURL(blob);

reader.onload = () => {
  const base64 = reader.result;
};

三、若依里更优雅的封装(推荐)

若依其实一般会封一个工具:

// utils/download.js
export function downloadBlob(data, filename) {
  const blob = new Blob([data]);
  const link = document.createElement("a");
  link.href = window.URL.createObjectURL(blob);
  link.download = filename;
  link.click();
}

使用:

downloadFile().then((res) => {
  downloadBlob(res.data, "报表.xlsx");
});

四、文件名怎么动态获取(重点)

后端一般会这样返回:

Content-Disposition: attachment; filename=xxx.xlsx

前端拿:

const disposition = res.headers["content-disposition"];

const fileName = decodeURIComponent(disposition.split("filename=")[1]);

五、常见坑(若依项目一定会遇到)

❌ 1. 返回 JSON 错误但你用 blob 接收

👉 结果:下载了一个“错误文件”

解决:

const reader = new FileReader();
reader.onload = () => {
  try {
    const json = JSON.parse(reader.result);
    console.error("接口报错", json);
  } catch (e) {
    // 正常文件
  }
};
reader.readAsText(res.data);

❌ 2. axios 拦截器把 blob 搞没了

若依默认拦截器:

return response.data;

👉 会导致你拿不到 headers(文件名)

✅ 正确:

return response;

❌ 3. 小程序(uniapp)特殊点

如果你是在 uniapp(微信小程序)

不能用 Blob,要用:

uni.downloadFile({
  url: "接口地址",
  success: (res) => {
    const tempFilePath = res.tempFilePath;
  },
});

👉 小程序是走文件系统,不是浏览器 Blob


六、有哪些现成插件(直接可用)

1️⃣ file-saver(最推荐)

👉 浏览器下载标准库

npm install file-saver
import { saveAs } from "file-saver";

saveAs(new Blob([res.data]), "文件.xlsx");

优点:

  • 兼容性好
  • 写法简单

2️⃣ js-file-download

npm install js-file-download
import fileDownload from "js-file-download";

fileDownload(res.data, "文件.xlsx");

3️⃣ 若依自带 download 方法(最推荐你用这个)

若依里通常已经有:

this.$download(url, params, filename);

👉 内部已经帮你处理好了 blob


七、总结(给你一套标准认知)

你可以这样理解整个链路:

后端(流)
   ↓
axios(responseType=blob)
   ↓
res.data(二进制)
   ↓
Blob
   ↓
URL.createObjectURL
   ↓
下载 / 预览

如果你要更深入(建议你下一步问我)

你现在这个阶段,我建议你下一步可以搞:

👉 若依源码里 download.js 是怎么封装的 👉 uniapp + Vue2 怎么统一处理文件流(坑很多) 👉 流式接口(SSE)+ 文件混合返回(你项目正在用)

我可以帮你直接做一套「若依 + uniapp 通用下载方案」。