Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Spring WebClient: How to stream large byte[] to file?

Tags:

It seems like it the Spring RestTemplate isn't able to stream a response directly to file without buffering it all in memory. What is the proper to achieve this using the newer Spring 5 WebClient?

WebClient client = WebClient.create("https://example.com"); client.get().uri(".../{name}", name).accept(MediaType.APPLICATION_OCTET_STREAM)                     ....? 

I see people have found a few workarounds/hacks to this issue with RestTemplate, but I am more interested in doing it the proper way with the WebClient.

There are many examples of using RestTemplate to download binary data but almost all of them load the byte[] into memory.

like image 865
Dave L. Avatar asked May 19 '19 17:05

Dave L.


People also ask

Which is better RestTemplate or WebClient?

RestTemplate will still be used. But in some cases, the non-blocking approach uses much fewer system resources compared to the blocking one. So, WebClient is a preferable choice in those cases.

Is WebClient multithreaded?

Because WebClient is immutable it is thread-safe. WebClient is meant to be used in a reactive environment, where nothing is tied to a particular thread (this doesn't mean you cannot use in a traditional Servlet application).

How do I handle WebClient exceptions?

While Initialising WebClient As mentioned in the code block, whenever a 5XX/4XX Error occurs, we can throw a user defined exception, and then execute error handling logic based on those user defined exceptions. Once this error Handler is defined, we can add it in the WebClient Initialisation.

What is the difference between retrieve and exchange in WebClient?

WebClient – retrieve() vs exchange()exchange method provides more control and details like status, headers and response body, etc. retrieve() method provides automatic error signal (e.g. 4xx and 5xx). No automatic error signal is available for exchange() method and we need to check status code and handle it.


1 Answers

With recent stable Spring WebFlux (5.2.4.RELEASE as of writing):

final WebClient client = WebClient.create("https://example.com"); final Flux<DataBuffer> dataBufferFlux = client.get()         .accept(MediaType.TEXT_HTML)         .retrieve()         .bodyToFlux(DataBuffer.class); // the magic happens here  final Path path = FileSystems.getDefault().getPath("target/example.html"); DataBufferUtils         .write(dataBufferFlux, path, CREATE_NEW)         .block(); // only block here if the rest of your code is synchronous  

For me the non-obvious part was the bodyToFlux(DataBuffer.class), as it is currently mentioned within a generic section about streaming of Spring's documentation, there is no direct reference to it in the WebClient section.

like image 75
Z4- Avatar answered Nov 24 '22 06:11

Z4-