Spring MVC
Async Streaming
File Handling
External Source
Java

How to async stream big file through Spring MVC from external source?

Interview Questions practice on Codemia

Over 8,000 real interview questions from top companies, searchable by company and role.

Browse interview questions

Introduction

If your Spring MVC endpoint proxies a large file from another service, the main goal is to avoid buffering the whole file in memory. The standard Spring MVC solution is to return a StreamingResponseBody, read from the upstream source in chunks, and write those bytes directly to the client response.

Why StreamingResponseBody Fits This Problem

StreamingResponseBody lets Spring handle the response asynchronously while your code writes directly to the output stream. That is a better fit than building a byte[] or Resource for very large responses, because the bytes can flow through the server incrementally.

This is especially useful when the file comes from an external HTTP source rather than local disk.

A Basic Proxy Controller

The example below uses Java’s HttpClient to fetch the upstream file as an InputStream, then streams it out through Spring MVC.

java
1import java.io.InputStream;
2import java.net.URI;
3import java.net.http.HttpClient;
4import java.net.http.HttpRequest;
5import java.net.http.HttpResponse;
6
7import org.springframework.http.HttpHeaders;
8import org.springframework.http.MediaType;
9import org.springframework.http.ResponseEntity;
10import org.springframework.web.bind.annotation.GetMapping;
11import org.springframework.web.bind.annotation.RestController;
12import org.springframework.web.servlet.mvc.method.annotation.StreamingResponseBody;
13
14@RestController
15public class DownloadController {
16
17    private final HttpClient httpClient = HttpClient.newHttpClient();
18
19    @GetMapping("/download")
20    public ResponseEntity<StreamingResponseBody> download() throws Exception {
21        HttpRequest request = HttpRequest.newBuilder()
22            .uri(URI.create("https://example.com/large-file.zip"))
23            .build();
24
25        HttpResponse<InputStream> upstream = httpClient.send(
26            request,
27            HttpResponse.BodyHandlers.ofInputStream()
28        );
29
30        StreamingResponseBody body = outputStream -> {
31            try (InputStream inputStream = upstream.body()) {
32                inputStream.transferTo(outputStream);
33            }
34        };
35
36        return ResponseEntity.ok()
37            .header(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=large-file.zip")
38            .contentType(MediaType.APPLICATION_OCTET_STREAM)
39            .body(body);
40    }
41}

The key idea is that the controller never loads the whole file into a byte array.

Configure Async Execution Explicitly

Spring recommends configuring the async executor used for streaming responses. If you leave it to defaults, a busy system can behave unpredictably under load.

java
1import org.springframework.context.annotation.Configuration;
2import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
3import org.springframework.web.servlet.config.annotation.AsyncSupportConfigurer;
4import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
5
6@Configuration
7public class WebConfig implements WebMvcConfigurer {
8    @Override
9    public void configureAsyncSupport(AsyncSupportConfigurer configurer) {
10        ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
11        executor.setCorePoolSize(4);
12        executor.setMaxPoolSize(16);
13        executor.setQueueCapacity(100);
14        executor.initialize();
15
16        configurer.setTaskExecutor(executor);
17        configurer.setDefaultTimeout(300_000);
18    }
19}

That gives streaming requests a predictable thread pool instead of relying on whatever default happens to be present.

Propagate Useful Response Headers

In a real proxy endpoint, you may also want to copy upstream headers such as content type, content length, or Content-Disposition. That improves the client experience and avoids guessing the file metadata.

Be selective. Forwarding every upstream header blindly is rarely a good idea.

Backpressure and Failure Behavior

Async streaming does not mean zero blocking. If the client reads slowly, the servlet output stream still determines how fast data can be written. The win is that you avoid materializing the whole response in memory and keep the controller model aligned with long-running transfers.

You should also decide what to do if the upstream request fails partway through. In many cases, the correct answer is to log the error and let the client receive a truncated or failed download rather than pretending the response completed successfully.

Common Pitfalls

  • Reading the full external file into memory defeats the purpose of streaming.
  • Forgetting to configure the async executor can cause poor behavior under load.
  • Ignoring upstream response status codes leads to broken downloads wrapped in 200 OK responses.
  • Copying every upstream header blindly can create incorrect downstream behavior.
  • Assuming async streaming removes all I/O blocking is unrealistic. It mainly improves memory usage and request handling structure.

Summary

  • Use StreamingResponseBody to proxy large files through Spring MVC without buffering them fully.
  • Read from the upstream source as a stream and write directly to the response output stream.
  • Configure Spring MVC async execution explicitly for production workloads.
  • Forward only the headers that matter to the client.
  • Treat streaming as a memory-efficient transfer pattern, not as magic non-blocking I/O everywhere.

Related reading
Course
Intermediate
27 lessons
14 hours
OOD Fundamentals

Master object-oriented design from first principles, SOLID, design patterns, and classic interview problems with hands-on coding.

View the course
Track what you have practised

A free account saves your progress, solutions and study plan across every problem on Codemia.

Interview Questions practice on Codemia

Over 8,000 real interview questions from top companies, searchable by company and role.

Browse interview questions

All Rights Reserved.