2

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.

Gordan Lin
  • 27
  • 1
  • 6
  • Does this answer your question? [How to best get a byte array from a ClientResponse from Spring WebClient?](https://stackoverflow.com/questions/44821187/how-to-best-get-a-byte-array-from-a-clientresponse-from-spring-webclient) – Toerktumlare Oct 26 '20 at 22:48

1 Answers1

2

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);
}
Chayne P. S.
  • 1,558
  • 12
  • 17
  • 4
    That works for me when I'm downloading small files, but errors out on large files. Is there a way to stream the result to the client so that the whole file isn't stored in memory? – Gordan Lin Oct 27 '20 at 20:42
  • mono is expecting to collect the stream in one go. Use of Flux, .bodyToFlux would solve this for large files – bh4r4th Oct 13 '22 at 23:46