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

Spring Boot+React文件下载报错:response.blob is not a function排查

解决React + Spring Boot文件下载的TypeError: response.blob is not a function问题

问题场景

基于Spring Boot和React实现文件下载功能,React端渲染包含下载路径的对象列表功能正常,但触发下载时出现错误:

Uncaught (in promise) TypeError: response.blob is not a function

Spring Boot端无报错,无法确认数据是否成功返回。

React组件代码(渲染列表)

function MyComponent(props) {
    return (
      <div style={{ display: "flex", flexWrap: "wrap" }}>
        {selectFileList.map((object) => (
          <div key={object.index} className={classes.fileDown}>
            <label htmlFor="file_down" className={classes.fileLabel}>
              <FileDownloadIcon />
              <div className={classes.fileDownSmall}>
                <a
                  id="file_down"
                  style={{
                    fontSize: "20px",
                    textDecoration: "none",
                    color: "white",
                  }}
                  onClick={() =>
                    fileDownload(object.bd_file_path, object.bd_file_nm)
                  }
                >
                  {object.bd_file_nm}
                </a>
              </div>
            </label>
          </div>
        ))}
      </div>
    );
  }

React下载触发函数

const fileDownload = async (path, name) => {
    const sendData = {
      file_path: path,
      file_nm: name,
    };
    await dispatch(fileAction.fileDownload(sendData))
      .then((response) => response.blob())
      .then((blob) => {
        const url = window.URL.createObjectURL(new Blob([blob]));
        const link = document.createElement("a");
        link.href = url;
        link.setAttribute("download", name);
        document.body.appendChild(link);
        link.click();
        link.parentNode.removeChild(link);
      });
  };

Spring Boot后端代码

@PostMapping("/fileDownload")
public void fileDownload(@RequestBody BoardFileDTO dto ,HttpServletResponse response) throws Exception {
    Path path = Paths.get(dto.getFile_path()).toAbsolutePath();
    File file = path.toFile();
    response.addHeader("Content-Type", Files.probeContentType(path));
    response.addHeader("Content-Disposition", "attachment; filename=" + dto.getFile_nm());
        
    InputStream inputStream = new FileInputStream(file);
    StreamUtils.copy(inputStream, response.getOutputStream());
    response.flushBuffer();
}

问题原因

  • 核心错误是dispatch返回的不是原生Fetch/XHR的Response对象:response.blob()是浏览器原生Response对象的方法,而你的Redux action(fileAction.fileDownload)处理后返回的结果并非这个原生对象,导致调用blob()时出现方法不存在的错误。
  • 和组件重复渲染无关,错误明确指向方法不存在,与渲染逻辑无关。

解决方案

1. 修正Redux Action的返回值

确保你的Redux action返回原生的HTTP响应对象(以Fetch为例):

// 示例Redux Action实现
export const fileDownload = (sendData) => {
  return async (dispatch) => {
    // 发送POST请求,返回原生Response对象
    const response = await fetch('/api/fileDownload', {
      method: 'POST',
      headers: {
        'Content-Type': 'application/json',
      },
      body: JSON.stringify(sendData)
    });
    
    // 可选:添加错误处理
    if (!response.ok) {
      throw new Error('文件下载请求失败');
    }
    
    // 返回原生response,供后续调用.blob()
    return response;
  };
};

2. 如果使用Axios,调整下载逻辑

如果你的Redux action用Axios发送请求,Axios的响应结构是{ data, status, headers },没有blob()方法,需要直接将response.data转为Blob:

const fileDownload = async (path, name) => {
  const sendData = { file_path: path, file_nm: name };
  const response = await dispatch(fileAction.fileDownload(sendData));
  
  // 从响应头获取Content-Type,或手动指定
  const contentType = response.headers['content-type'] || 'application/octet-stream';
  const blob = new Blob([response.data], { type: contentType });
  
  const url = window.URL.createObjectURL(blob);
  const link = document.createElement('a');
  link.href = url;
  link.setAttribute('download', name);
  document.body.appendChild(link);
  link.click();
  link.parentNode.removeChild(link);
};

3. 优化Spring Boot后端实现(可选)

使用Spring提供的ResponseEntity<Resource>代替直接操作HttpServletResponse,更符合规范且能自动处理响应头:

import org.springframework.core.io.FileSystemResource;
import org.springframework.core.io.Resource;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.net.URLEncoder;

@PostMapping("/fileDownload")
public ResponseEntity<Resource> fileDownload(@RequestBody BoardFileDTO dto) throws Exception {
    Path path = Paths.get(dto.getFile_path()).toAbsolutePath();
    Resource resource = new FileSystemResource(path.toFile());
    
    // 处理中文文件名乱码问题
    String encodedFileName = URLEncoder.encode(dto.getFile_nm(), StandardCharsets.UTF_8.toString());
    
    return ResponseEntity.ok()
            .contentType(MediaType.parseMediaType(Files.probeContentType(path)))
            .header(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=\"" + encodedFileName + "\"")
            .body(resource);
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.07 16:50:22