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

Spring Boot返回PDF/图片API响应空白,求助正确处理方案

问题场景

在Spring Boot + React项目中,需实现API:前端传入文件名,后端返回文件内容并在浏览器新标签页展示。当前后端读取文件字节写入本地可生成正常PDF,但前端获取后打开的PDF为空白文档,尝试多种字节转换方式均无效。

问题核心分析

后端读取文件逻辑本身无问题,但前端请求未正确处理二进制数据——默认响应格式会将二进制转为字符串,导致字节损坏;同时后端响应头可进一步优化,确保浏览器正确识别文件展示方式。


后端修正方案

直接使用FileSystemResource替代ByteArrayResource,避免字节复制的潜在问题,同时完善响应头配置:

服务层代码修改

public ResponseEntity<Resource> findFileContent(String fileName) throws CommonException {
    try {
        String fileUrl = leaveAttachmentUploadPath;
        Path path = Paths.get(fileUrl + "/" + fileName);
        FileSystemResource resource = new FileSystemResource(path.toFile());
        
        HttpHeaders headers = new HttpHeaders();
        String extension = FilenameUtils.getExtension(fileName);
        
        if(extension.equalsIgnoreCase("pdf")) {
            headers.setContentType(MediaType.APPLICATION_PDF);
        } else if(extension.equalsIgnoreCase("jpg") || extension.equalsIgnoreCase("jpeg")) {
            headers.setContentType(MediaType.IMAGE_JPEG);
        } else if(extension.equalsIgnoreCase("png")) {
            headers.setContentType(MediaType.IMAGE_PNG);
        }
        
        // 设置为inline,让浏览器直接打开而非触发下载
        headers.setContentDisposition(ContentDisposition.inline().filename(fileName).build());
        
        return ResponseEntity.status(HttpStatus.OK)
                .contentLength(resource.contentLength())
                .headers(headers)
                .body(resource);
    } catch (Exception ex) {
        log.error("Exception occurred during file content fetch", ex);
        throw new CommonException(HttpStatus.INTERNAL_SERVER_ERROR, ex.getMessage());
    }
}

前端修正方案

核心是请求时指定responseType: 'arraybuffer',确保获取原始二进制数据,无需额外字符编码转换:

基于封装请求的代码修改

// 假设rest.fetchAttchment是axios封装,需添加responseType配置
let fileUrlResponse = await rest.fetchAttchment(fileName[0].fileName, {
    responseType: 'arraybuffer' // 关键:指定响应为二进制数组
});

let data = fileUrlResponse.data;
let contentType = fileUrlResponse.headers['content-type'];

// 直接用arraybuffer创建Blob
const file = new Blob([data], { type: contentType });
const fileURL = URL.createObjectURL(file);
window.open(fileURL, '_blank');

// 可选:标签页关闭后释放URL,避免内存泄漏
setTimeout(() => {
    URL.revokeObjectURL(fileURL);
}, 1000);

直接使用axios的示例代码

import axios from 'axios';

async function openFile(fileName) {
    try {
        const response = await axios.get('/api/get-file-view', {
            params: { fileName },
            responseType: 'arraybuffer' // 必须设置
        });
        
        const contentType = response.headers['content-type'];
        const blob = new Blob([response.data], { type: contentType });
        const url = URL.createObjectURL(blob);
        window.open(url, '_blank');
        
        setTimeout(() => URL.revokeObjectURL(url), 1000);
    } catch (err) {
        console.error('获取文件失败:', err);
    }
}

关键注意事项

  • 前端必须设置responseType: 'arraybuffer',否则二进制数据会被转为UTF-8字符串,导致PDF等文件损坏。
  • 后端设置Content-Disposition: inline,确保浏览器尝试直接打开文件,而非触发下载弹窗。
  • 使用FileSystemResource比ByteArrayResource更高效,尤其处理大文件时,避免一次性将文件全部加载到内存。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.13 00:45:19