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
相关产品推荐
相关产品推荐

