Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to stream binary data in a response body in Spring WebFlux

I am making a project using Spring WebFlux.

In the past I had used StreamingResponseBody for streaming responses back to the client, but I can't find the equivalent in WebFlux.

Example:

import org.springframework.web.servlet.mvc.method.annotation.StreamingResponseBody;

@GetMapping("/video")
public StreamingResponseBody stream() {
    InputStream videoStream = ...
    StreamingResponseBody res = (os) -> { IOUtils.copy(videoStream, os); }
    return res;
}

Is there an equivalent of StreamingResponseBody for WebFlux? or, should I import the traditional Spring MVC and mix them?

Edit: So far I am solving it by accessing the ServerHttpResponse (example below). But I am still wondering about better solutions.

@GetMapping("/video")
fun stream2(response: ServerHttpResponse): Mono<Void> {
    val factory = response.bufferFactory()
    val publisher = videoStream
            .observeVideoParts()
            .map { factory.wrap(it.bytes) }
    return response.writeWith(publisher)
}
like image 728
ESala Avatar asked Dec 23 '17 17:12

ESala


2 Answers

A little bit late. However, scanning the recent documentation of Spring core and Webflux, I think the following should work:

@GetMapping("/stream/{path}")
public Flux<DataBuffer> getVideo(
        @PathVariable("path") String path,
        ServerHttpResponse response
) {
    return DataBufferUtils.read(
            new FileSystemResource(path),
            response.bufferFactory(),
            512
    );
}
like image 97
PeMa Avatar answered Sep 29 '22 22:09

PeMa


For now, the best solution that I have found is to return a ServerHttpResponse.

Since ServerHttpResponse only allows to write DataBuffer objects but not ByteArray objects, I made an extension function that wraps them before writing:

fun ServerHttpResponse.writeByteArrays(bytes: Flux<ByteArray>): Mono<Void> {
    val factory = this.bufferFactory()
    val dataBuffers = bytes.map { factory.wrap(it) }
    return this.writeWith(dataBuffers)
}

Then a Flux<ByteArray> can simply be written like this:

@GetMapping("/video")
fun stream2(response: ServerHttpResponse): Mono<Void> {
    val videoParts: Flux<ByteArray> = ...
    return response.writeByteArrays(videoParts)
}

I am still open to other solutions.

like image 29
ESala Avatar answered Oct 23 '22 12:10

ESala