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

Spring 4.3.14使用InputStreamResource下载文件损坏问题求助

Troubleshooting Corrupted File Downloads with InputStreamResource in Spring 4.3.14

Hey there, let's break down why your file downloads are getting corrupted when using InputStreamResource in Spring 4.3.14, and fix it up.

Root Cause

The main issue here boils down to how InputStreamResource interacts with Spring's ResourceHttpMessageConverter:

  • Unlike ByteArrayResource which holds your entire file content in memory, InputStreamResource generates a fresh input stream every time getInputStream() is called.
  • In Spring 4.3.x, ResourceHttpMessageConverter first calls resource.contentLength() to calculate the file size. For InputStreamResource, this method reads the entire stream to get the length—by the time the converter tries to write the stream to the response, the stream pointer is already at the end, resulting in incomplete or empty (corrupted) files.

Solutions

1. Switch to ByteArrayResource (Best for Small-to-Medium Files)

Replace InputStreamResource with ByteArrayResource, which safely supports multiple stream reads since it stores content in memory. Here's a complete controller example:

@RequestMapping(value = "/download", method = RequestMethod.GET)
public ResponseEntity<Resource> downloadFile() throws IOException {
    // Replace with your actual file source (local file, DB blob, etc.)
    File targetFile = new File("/path/to/your/file.pdf");
    byte[] fileContent = Files.readAllBytes(targetFile.toPath());
    ByteArrayResource resource = new ByteArrayResource(fileContent);

    return ResponseEntity.ok()
            // Trigger browser save dialog
            .header(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=\"" + targetFile.getName() + "\"")
            // Explicitly set content length to avoid browser guessing
            .contentLength(fileContent.length)
            // Adjust media type to match your file type
            .contentType(MediaType.APPLICATION_PDF)
            .body(resource);
}

2. Use StreamingResponseBody (Best for Large Files)

If your files are too big to load into memory, use StreamingResponseBody. This approach streams content directly to the response without holding the entire file in memory, and avoids the repeated stream reads that break InputStreamResource:

@RequestMapping(value = "/download", method = RequestMethod.GET)
public ResponseEntity<StreamingResponseBody> downloadLargeFile() throws IOException {
    File largeFile = new File("/path/to/large/file.zip");
    InputStream fileInputStream = new FileInputStream(largeFile);

    StreamingResponseBody responseBody = outputStream -> {
        byte[] buffer = new byte[4096]; // 4KB buffer for efficient streaming
        int bytesRead;
        while ((bytesRead = fileInputStream.read(buffer)) != -1) {
            outputStream.write(buffer, 0, bytesRead);
        }
        // Clean up resources
        fileInputStream.close();
    };

    return ResponseEntity.ok()
            .header(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=\"" + largeFile.getName() + "\"")
            .contentLength(largeFile.length())
            .contentType(MediaType.APPLICATION_OCTET_STREAM)
            .body(responseBody);
}

3. Bonus: Simplify Your WebMvcConfig

You don't need to explicitly add ResourceHttpMessageConverter to the converters list—Spring 4.3.x registers it by default. Removing that custom configuration can avoid accidental conflicts with default converter behavior.

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.21 07:41:33