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

