You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

React前端如何读取Java返回的OutputStream文件流并实现下载

问题原因&修复方案

1 后端Java侧修正

现有后端代码存在两个问题:跨域场景下前端无法读取Content-Disposition响应头,文件名含中文/特殊字符时会乱码,修正后的代码如下:

import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;

// 原有逻辑
if (Files.exists(filePath)) {
    response.setContentType(Files.probeContentType(filePath));
    // 跨域场景下暴露Content-Disposition头,允许前端读取
    response.setHeader("Access-Control-Expose-Headers", "Content-Disposition");
    // 文件名编码,避免中文/特殊字符乱码,替换+为%20兼容空格解码
    String fileName = URLEncoder.encode(file.getName(), StandardCharsets.UTF_8.name()).replaceAll("\\+", "%20");
    response.addHeader("Content-Disposition", "attachment; filename=" + fileName);
    Files.copy(filePath, response.getOutputStream());
    response.getOutputStream().flush();
}

2 前端React侧修正

现有代码的问题有两个:

  • 发送请求时未指定响应类型为blob,导致二进制文件数据被默认解析为文本格式损坏
  • 没有正确从响应头解析文件名,你使用的response.filename是不存在的自定义属性

2.1 基于Axios请求的修正方案

首先请求时指定响应类型配置:

// 发GET请求时必须添加responseType配置
const response = await axios.get('/你的下载接口地址', {
  params: { /* 你的请求参数 */ },
  responseType: 'blob' // 告诉axios返回二进制数据,不可省略
})

然后修正下载逻辑:

// 从响应头解析文件名
const disposition = response.headers['content-disposition']
let fileName = '默认文件名' // 解析失败时的兜底文件名
if (disposition && disposition.indexOf('filename=') !== -1) {
  fileName = decodeURIComponent(disposition.split('filename=')[1])
}
// 执行下载逻辑
const url = window.URL.createObjectURL(new Blob([response.data]));
const link = document.createElement('a');
link.href = url;
link.setAttribute('download', fileName);
document.body.appendChild(link);
link.click();
// 手动清理内存,避免内存泄漏
document.body.removeChild(link);
window.URL.revokeObjectURL(url);

2.2 基于原生Fetch请求的修正方案

fetch('/你的下载接口地址?' + new URLSearchParams({ /* 你的请求参数 */ }))
  .then(res => {
    // 解析文件名
    const disposition = res.headers.get('Content-Disposition')
    let fileName = '默认文件名'
    if (disposition && disposition.includes('filename=')) {
      fileName = decodeURIComponent(disposition.split('filename=')[1])
    }
    return Promise.all([res.blob(), Promise.resolve(fileName)])
  })
  .then(([blob, fileName]) => {
    // 执行下载逻辑
    const url = window.URL.createObjectURL(blob);
    const link = document.createElement('a');
    link.href = url;
    link.download = fileName;
    document.body.appendChild(link);
    link.click();
    // 手动清理内存
    document.body.removeChild(link);
    window.URL.revokeObjectURL(url);
  })

校验点

  • 本地调试接口跨域时,确保代理配置不会过滤掉Content-Disposition响应头
  • 文件名存在特殊字符时,确保前后端编码、解码格式统一,避免乱码

内容的提问来源于stack exchange,提问作者rudeTool

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.28 23:06:08