How to Download Large Files Efficiently with Spring RestTemplate and Resume Support
This tutorial explains how to use Spring's RestTemplate to download large files without exhausting memory, covering pitfalls of default methods, implementing a custom ResponseExtractor to stream data to disk, and adding support for resumable downloads via Range headers.
Overview
In this tutorial we demonstrate several techniques for downloading large files with Spring's RestTemplate.
RestTemplate
RestTemplate is a synchronous, blocking HTTP client introduced in Spring 3. It may be deprecated in future versions in favor of the non‑blocking WebClient introduced in Spring 5.
Pitfalls
Downloading a file directly into memory can cause OutOfMemoryError. Using ResourceHttpMessageConverter loads the whole response into a ByteArrayInputStream, still causing memory pressure. Configuring ResourceHttpMessageConverter#supportsReadStreaming to return InputStreamResource fails because the underlying execute method closes the response stream before the input stream can be read.
Solution
Two possible solutions are:
Write a custom HttpMessageConverter that supports File as the return type.
Use RestTemplate.execute together with a custom ResponseExtractor to stream the response directly to a file.
We focus on the second approach.
Implementation of a non‑resumable download
File file = restTemplate.execute(
FILE_URL,
HttpMethod.GET,
null,
clientHttpResponse -> {
File ret = File.createTempFile("download", "tmp");
StreamUtils.copy(clientHttpResponse.getBody(),
new FileOutputStream(ret));
return ret;
});
Assertions.assertNotNull(file);
Assertions.assertThat(file.length()).isEqualTo(contentLength);Checking server support for range requests
HttpHeaders headers = restTemplate.headForHeaders(FILE_URL);
Assertions.assertThat(headers.get("Accept-Ranges")).contains("bytes");
Assertions.assertThat(headers.getContentLength()).isGreaterThan(0);Implementation of a resumable download
File file = /* previously downloaded part */;
restTemplate.execute(
FILE_URL,
HttpMethod.GET,
request -> request.getHeaders().set(
"Range",
String.format("bytes=%d-%d", file.length(), contentLength)),
response -> {
StreamUtils.copy(response.getBody(),
new FileOutputStream(file, true));
return file;
});
Assertions.assertThat(file.length()).isLessThanOrEqualTo(contentLength);When content length is unknown
String rangeHeader = String.format("bytes=%d-", file.length());
request.getHeaders().set("Range", rangeHeader);Conclusion
We discussed common problems when downloading large files and provided a RestTemplate‑based solution, including a method for resumable (range) downloads. The full source code is available in the linked GitHub repository.
Signed-in readers can open the original source through BestHub's protected redirect.
This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactand we will review it promptly.
Programmer DD
A tinkering programmer and author of "Spring Cloud Microservices in Action"
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
