Search code examples
javaspringspring-webfluxreactive

Spring Webflux Rest Controller for image response correct return type


I am creating a Spring WebFlux Controller that returns an image. I have tried this option below, based on similar questions.

@RestController
@RequestMapping(value = "/image/*")
public class ImageController {
@RequestMapping(method = RequestMethod.GET, produces = MediaType.IMAGE_PNG_VALUE)
    protected void doGet(ServerHttpRequest request, ServerHttpResponse response) {
       try {
            ByteArrayOutputStream baos = new ByteArrayOutputStream();
            ImageIO.write(img, "jpg", baos);
            DataBuffer imageData = response.bufferFactory().wrap(barr);
            //returns empty content in response
            //response.writeWith(Flux.just(imageData));
            //returns valid image
            response.writeWith(Flux.just(imageData)).block();
            } catch (Exception e) {
                e.printStackTrace();
            } 
        }

The image is valid and I can also see that the DataBuffer has the bytes. However it is not sending the response back to the client.

The response to this service is successful (status 200), but the payload is empty (0 Bytes).

Can anyone identify the error here?

[UPDATE]

I got the Controller to return the image by adding the call to block:

response.writeWith(Flux.just(imageData)).block();

I also see that it works by calling subscribe():

response.writeWith(Flux.just(imageData)).subscribe();

What is the right approach for this type of controller? Is this equivalent to a flush() call on a Stream? Shouldn't the WebFlux framework block or flush the response object after the controller method is completed?

Similar questions:

How to write messages to http body in Spring webflux WebExceptionHandlder

https://stackoverflow.com/a/58351771/6352160


Solution

  • Here is how I got this to work. It was a simple problem, but I was following the same approach used for traditional Spring MVC (to write the image as a byte stream into the servlet response).

     @GetMapping(produces = MediaType.IMAGE_PNG_VALUE)
     public Mono<DataBuffer> doGet(ServerHttpRequest request) {
        try {
            ByteArrayOutputStream baos = new ByteArrayOutputStream();
            ImageIO.write(img, "png", baos);
            baos.close();
            byte[] barr = baos.toByteArray();
            DataBuffer imageData =  
               DefaultDataBufferFactory.sharedInstance.wrap(barr);
            return Mono.just(imageData);
        } catch (Exception e) {
            LOG.error("An unknown IO error occurred while writing pixel", e);
        } 
        return Mono.empty();
    }