Рубрики
Без рубрики

Сервер-Отправленные события весной

Изучите концепцию API на основе серверных событий с помощью Spring.

Автор оригинала: Ger Roza.

1. Обзор

В этом учебнике мы увидим, как мы можем реализовать API на основе серверных отправлений с помощью Spring.

Проще говоря, Server-Sent-Events, или SSE для краткости, является стандартом HTTP, который позволяет веб-приложению обрабатывать однонаправленный поток событий и получать обновления всякий раз, когда сервер испускает данные.

Весенняя версия 4.2 уже поддержала его, но начиная с весны 5, у нас теперь есть более идиотизм и удобный способ справиться с этим.

2. SSE с весной 5 Webflux

Для достижения этой цели мы можем использовать такие реализации, как Флюс класс, предоставляемый Реактор библиотеки, или, возможно, СерверСентевент сущность , что дает нам контроль над метаданными событий.

2.1. Поток событий с использованием потока

Флюс является реактивным представлением потока событий – оно обрабатывается по-разному в зависимости от указанного типа средств массовой информации запроса или ответа.

Чтобы создать конечную точку потоковой передачи SSE, нам придется следить за Спецификации W3C и обозначить его тип MIME как текстовые/событийные потоки :

@GetMapping(path = "/stream-flux", produces = MediaType.TEXT_EVENT_STREAM_VALUE)
public Flux streamFlux() {
    return Flux.interval(Duration.ofSeconds(1))
      .map(sequence -> "Flux - " + LocalTime.now().toString());
}

тем интервал метод создает поток который излучает длинный значения постепенно. Затем мы сопоставим эти значения с желаемым результатом.

Давайте начнем наше приложение и попробовать его, просматривая конечную точку тогда.

Мы увидим, как браузер реагирует на события, подталкиваемые вторым за вторым сервером. Для получения дополнительной информации о Флюс и Реактор Основные , мы можем проверить этот пост .

2.2. Использование элемента ServerSentEvent

Теперь мы обернем наш выходной Струнные в СерверСентСевент объект, и изучить преимущества этого:

@GetMapping("/stream-sse")
public Flux> streamEvents() {
    return Flux.interval(Duration.ofSeconds(1))
      .map(sequence -> ServerSentEvent. builder()
        .id(String.valueOf(sequence))
          .event("periodic-event")
          .data("SSE - " + LocalTime.now().toString())
          .build());
}

Как мы можем оценить, есть несколько преимуществ использования СерверСентевент сущность :

  1. мы можем обрабатывать метаданные событий, которые нам нужны в реальном сценарии
  2. мы можем игнорировать ” текстовые/событийные потоки ” Декларация типа СМИ

В данном случае мы уточнили id , название мероприятия , и, самое главное, фактическое данные события.

Кроме того, мы могли бы добавить комментарии атрибут, и повторить значение, в котором будет указано время повторного подключения, которое будет использоваться при попытке отправки события.

2.3. Потребление серверных событий с помощью WebClient

Теперь давайте использовать наш поток событий с WebClient .:

public void consumeServerSentEvent() {
    WebClient client = WebClient.create("http://localhost:8080/sse-server");
    ParameterizedTypeReference> type
     = new ParameterizedTypeReference>() {};

    Flux> eventStream = client.get()
      .uri("/stream-sse")
      .retrieve()
      .bodyToFlux(type);

    eventStream.subscribe(
      content -> logger.info("Time: {} - event: name[{}], id [{}], content[{}] ",
        LocalTime.now(), content.event(), content.id(), content.data()),
      error -> logger.error("Error receiving SSE: {}", error),
      () -> logger.info("Completed!!!"));
}

тем подписываться метод позволяет нам указать, как мы будем действовать, когда мы получим событие успешно, когда происходит ошибка, и когда потоковая передача будет завершена.

В нашем примере мы использовали получить метод, который является простым и простым способом получения тела ответа.

Этот метод автоматически бросает WebClientРеспонцииЭкспоследование если мы получим ответ 4xx или 5xx, если мы не справимся со сценариями, добавляя onStatus утверждение.

С другой стороны, мы могли бы использовать обменные метод, который обеспечивает доступ к КлиентОтветчик а также не сигнализирует об ошибках при невыполнех ответов.

Мы должны учитывать, что мы можем обойти СерверСентевент обертка, если нам не нужны метаданные события.

3. SSE Потоковое весной MVC

Как мы уже говорили, спецификация SSE поддерживается с весны 4.2, когда SseEmitter класс был введен.

Проще говоря, мы определим ИсполнительСервис , нить, где SseEmitter будет делать свою работу нажатия данных, и вернуть экземпляр излучатель, сохраняя соединение открытым таким образом:

@GetMapping("/stream-sse-mvc")
public SseEmitter streamSseMvc() {
    SseEmitter emitter = new SseEmitter();
    ExecutorService sseMvcExecutor = Executors.newSingleThreadExecutor();
    sseMvcExecutor.execute(() -> {
        try {
            for (int i = 0; true; i++) {
                SseEventBuilder event = SseEmitter.event()
                  .data("SSE MVC - " + LocalTime.now().toString())
                  .id(String.valueOf(i))
                  .name("sse event - mvc");
                emitter.send(event);
                Thread.sleep(1000);
            }
        } catch (Exception ex) {
            emitter.completeWithError(ex);
        }
    });
    return emitter;
}

Всегда убедитесь, что выбрать правильный ИсполнительСервис для вашего сценария использования.

Мы можем узнать больше о SSE весной MVC и взглянуть на другие примеры, прочитав этот интересный учебник .

4. Понимание событий, отправленных сервером

Теперь, когда мы знаем, как реализовать конечные точки SSE, давайте попробуем пойти немного глубже, понимая некоторые основные понятия.

SSE — это спецификация, принятая большинством браузеров, которая позволяет однонаправленно разрешать потоковые события в любое время.

«События» — это всего лишь поток закодированных текстовых данных UTF-8, которые следуют формату, определяемому спецификацией.

Этот формат состоит из ряда элементов ключевого значения (id, retry, данных и событий, которые указывают имя), разделенных разрывами строк.

Комментарии также поддерживаются.

Спецификация не ограничивает формат полезной нагрузки данных в любом случае; мы можем использовать простой струна или более сложной структуры JSON или XML.

И последний момент, который мы должны принять во внимание, это разница между использованием потоковой передачи SSE WebSockets .

пока Веб-Сокеты предлагают полноправную (двунаправленную) связь между сервером и клиентом, в то время как SSE использует однонаправленную связь.

Кроме того, WebSockets не является протоколом HTTP и, в противоположность SSE, он не предлагает стандарты обработки ошибок.

5. Заключение

Подводя итог, в этой статье мы узнали основные концепции потоковой передачи SSE, которая, несомненно, является большим ресурсом, который позволит нам создавать системы следующего поколения.

Сейчас мы находимся в отличном положении, чтобы понять, что происходит под капотом, когда мы используем этот протокол.

Кроме того, мы дополнили теорию простыми примерами, которые можно найти в наш репозиторий Github .