JDK 17+Spring Boot 3.2.5文件流返回0字节,JDK8正常求排查
问题修复:JDK17+SpringBoot3.2.5下StreamingResponseBody返回0字节
问题根源
你的代码先通过Files.readAllBytes把整个文件加载到内存,再用ByteArrayInputStream转写,这种方式在SpringBoot3.x(配合JDK17)的响应处理逻辑下,可能出现流未正确刷新或文件读取时机异常的问题;另外finally里的文件删除操作虽已读进内存,但不排除JDK17的IO优化导致的隐性异常。
修复后的代码
File file = new File(filePath); // 文件权限设置按需保留,若文件本身权限足够可移除 file.setExecutable(false); file.setReadable(true); file.setWritable(true); // 创建StreamingResponseBody,直接从文件读取流输出 StreamingResponseBody responseBody = outputStream -> { try (InputStream inputStream = Files.newInputStream(Paths.get(filePath))) { byte[] buffer = new byte[4096]; int bytesRead; while ((bytesRead = inputStream.read(buffer)) != -1) { outputStream.write(buffer, 0, bytesRead); // 手动刷新输出流,确保数据即时写出 outputStream.flush(); } } catch (IOException e) { throw new RuntimeException("Error streaming PDF", e); } finally { // 确保流完全写出后再删除文件 deleteUserPrintDir(filePath, file); } }; return ResponseEntity.ok() // 采用标准格式支持中文文件名,避免乱码(可选但推荐) .header("Content-Disposition", String.format("attachment; filename*=UTF-8''%s", URLEncoder.encode(file.getName(), StandardCharsets.UTF_8.name()))) .contentType(MediaType.APPLICATION_PDF) .body(responseBody);
关键修改点
- 直接操作文件流:放弃先读入内存的方式,改用
Files.newInputStream直接读取文件,减少内存占用的同时适配JDK17的IO逻辑。 - 添加流刷新:每次写入后调用
outputStream.flush(),避免SpringBoot3.x的响应缓冲机制导致数据未及时输出。 - 修正响应头格式:使用RFC 5987标准的
filename*格式,兼容现代客户端并解决文件名乱码问题。 - 移除冗余代码:删除
data=null、path=null这类手动置空操作,JVM垃圾回收会自动处理对象回收。
内容的提问来源于stack exchange,提问作者rajan gupta
相关产品推荐
相关产品推荐

