Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Producing Server Sent Events in Spring Boot Webflux

I have the following code in a SpringBoot application:

class MySse {
    public Mono<ServerResponse> emitEvents(ServerRequest request){
        return ServerResponse.ok()
                .contentType(MediaType.TEXT_EVENT_STREAM)
                .body(Mono.from(Flux.interval(Duration.ofSeconds(1))
                .map(sequence  -> ServerSentEvent.builder()
                        .id(String.valueOf(sequence))
                        .event("periodic-event")
                        .data("SSE - " + LocalTime.now().toString())
                        .build())), ServerSentEvent.class);
    }
}

@Configuration
public class MyRoutesConfiguration {

    @Autowired
    @Bean
    RouterFunction<ServerResponse> sseRoute(MySse mySse) {
        return route(path("/sse").and(method(HttpMethod.GET)), MySse ::emitEvents)
                ;
    }

    @Bean
    public MySse mySse() {
        return new MySse();
    }
}

If I navigate to http://localhost (route not shown above but it works) from there I open DevTools in Chrome and type in the following JavaScript code:

const evtSource = new EventSource("sse/");
evtSource.onmessage = function(event) {
  console.log(event.data);
}

But nothing is printed out...

Breakpoints in the map(...) lambda in MySse::emitEvent are hit every second

But nothing is printed out in the browswer's JS console.

if I visit http://localhost/sse I get the following response:

id:0
event:periodic-event
data:SSE - 20:17:12.972706400
like image 584
auser Avatar asked Oct 16 '25 06:10

auser


1 Answers

public Mono<ServerResponse> emitEvents(ServerRequest request){

    return ServerResponse.ok()
            .contentType(MediaType.TEXT_EVENT_STREAM)
            .body(BodyInserters.fromServerSentEvents(Flux.interval(Duration.ofSeconds(1))
            .map(aLong -> ServerSentEvent.<String>builder()
                            .id(String.valueOf(aLong))
                            .event("periodic-event")
                            .data("SSE - " + LocalTime.now().toString())
                            .build())));
}

if you want to stream the data you need to return a Flux. A Mono is ONE item, a Flux is 0...n items. You trigger the Flux to start emitting on each second interval and as long as the connection is open it will emit an event back to the calling client each second.

you can try it out with for example curl (or the chrome console as you are using) but you need to disable the curl buffering strategy using the -N flag if you are using curl.

curl -N http://localhost:8080/sse
like image 186
Toerktumlare Avatar answered Oct 18 '25 21:10

Toerktumlare



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!