How do you use Spring WebClient as a file download passthru

Viewed 1735

I am trying to use WebClient to download a file from a external service and return it to the client. In the Rest Controller, I have the following endpoint:

@GetMapping(value = "/attachment/{fileId}", produces = MediaType.APPLICATION_OCTET_STREAM_VALUE)
public Flux<byte[]> get(@PathVariable String fileId) {

    return this.webClient.get()
            .uri(builder ->
                    builder.scheme("https")
                            .host("external-service.com")
                            .path("/{fileId}")
                            .build(fileId)
            ).attributes(clientRegistrationId("credentials"))
            .accept(MediaType.APPLICATION_OCTET_STREAM)
            .retrieve()
            .bodyToFlux(byte[].class);
}

When I try to hit the endpoint, I get the following error:

Exception Class:class org.springframework.http.converter.HttpMessageNotWritableException
Stack Trace:org.springframework.http.converter.HttpMessageNotWritableException: No converter for [class org.springframework.web.servlet.mvc.method.annotation.ReactiveTypeHandler$CollectedValuesList] with preset Content-Type 'null'
    at org.springframework.web.servlet.mvc.method.annotation.AbstractMessageConverterMethodProcessor.writeWithMessageConverters(AbstractMessageConverterMethodProcessor.java:317)
    at org.springframework.web.servlet.mvc.method.annotation.RequestResponseBodyMethodProcessor.handleReturnValue(RequestResponseBodyMethodProcessor.java:181)

I have tried returning Flux<DataBuffer> instead, but getting the same error message.

I'm using spring-boot-starter-web and spring-boot-starter-webflux version 2.2.4.RELEASE. It is running on a tomcat server.

What am I missing?

Edit: I'm trying to stream the result to the client without buffering the whole file into memory.

1 Answers

This works for me. Just change from Flux to Mono. Seem there is no converter for Flux<byte[]>

@GetMapping(value = "/attachment/{fileId}", produces = MediaType.APPLICATION_OCTET_STREAM_VALUE)
public Mono<byte[]> get(@PathVariable String fileId) {

    return this.webClient.get()
            .uri(builder ->
                    builder.scheme("https")
                            .host("external-service.com")
                            .path("/{fileId}")
                            .build(fileId)
            ).attributes(clientRegistrationId("credentials"))
            .accept(MediaType.APPLICATION_OCTET_STREAM)
            .retrieve()
            .bodyToMono(byte[].class);
}
Related