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

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.14 23:37:34