Создание событий, отправленных сервером, в Spring Boot Webflux - PullRequest
1 голос
/ 02 августа 2020

У меня есть следующий код в приложении SpringBoot:

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();
    }
}

Если я перейду к http://localhost (маршрут не показан выше, но он работает) оттуда я открываю DevTools в Chrome и набираю следующий код JavaScript:

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

Но ничего не распечатывается ...

Точки останова в map(...) лямбде в MySse::emitEvent срабатывают каждую секунду

Но в консоли браузера JS ничего не выводится.

при посещении http://localhost/sse я получаю следующий ответ:

id:0
event:periodic-event
data:SSE - 20:17:12.972706400

1 Ответ

2 голосов
/ 03 августа 2020
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())));
}

, если вы хотите передавать данные, вам нужно вернуть Flux. Mono - это ОДИН элемент, Flux - 0...n элемент. Вы запускаете Flux, чтобы начать излучение в каждом втором интервале, и пока соединение открыто, он будет отправлять событие обратно вызывающему клиенту каждую секунду.

вы можете попробовать это, например, с помощью curl ( или консоль chrome, как вы используете), но вам нужно отключить стратегию буферизации curl с помощью флага -N, если вы используете curl.

curl -N http://localhost:8080/sse
...