HTML5 EventSource отправка нескольких запросов

Я пытаюсь реализовать отправленные события сервера, используя Spring SseEmitter, как описано в этом видео на Youtube.

Я могу инициировать поток событий и получать данные с отправленного сервером события.

Тем не менее, я вижу несколько EventStream Напечатайте запросы, запущенные с клиента и поступающие на сервер. Как я понимаю, EventSource следует отправить один HTTP запрос, а затем должен поддерживать half duplex соединение с сервера, с помощью которого сервер отправляет события клиенту.

Почему тогда отправка запросов через регулярные промежутки времени? Разве это не похоже на опрос вместо полудуплексного соединения?

Ниже приведен код, который я использую.

Код сервера

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.servlet.mvc.method.annotation.SseEmitter;
import org.springframework.web.servlet.mvc.method.annotation.SseEmitter.SseEventBuilder;

@RestController
public class TestService {
    private List<SseEmitter> subscriberList = Collections.synchronizedList(new ArrayList<>());

    @RequestMapping("inbox")
    public SseEmitter inbox() {
        SseEmitter subscriber = new SseEmitter();
        subscriberList.add(subscriber);

        subscriber.onCompletion(() -> {
            subscriberList.remove(subscriber);
            System.out.println("Removed the completed event emitter");
        });

        System.out.println("Subscriber arrived");
        return subscriber;
    }

    @RequestMapping("message")
    public String message(@RequestParam("message") String message) {
        System.out.println("SubscriberList size " + subscriberList.size());
        for(SseEmitter subscriber : subscriberList) {
            try {
                SseEventBuilder eventBuilder = SseEmitter.event().name("group1").data(message);
                subscriber.send(eventBuilder);
            } catch (Exception e) {
                e.printStackTrace();
            }   
        };
        return message;
    }
}

Код клиента

$(function () {
    console.log("Started");
    var eventSource = new EventSource("/inbox");
    eventSource.addEventListener('error', function(e) {
      if (e.currentTarget.readyState == EventSource.CLOSED) {
          console.log("Connection is closed")
      } else {
        source.close();
        console.log("Closing connection");
      }
    });
    eventSource.addEventListener("group1", function (event) {
        console.log(event.data);
        document.querySelector("body").innerHTML += "<div>" + event.data + "</div>";
    });
});

Ниже приведен скриншот вкладки сети клиента от Chrome

Вот журнал на стороне сервера

Subscriber arrived
Removed the completed event emitter
Subscriber arrived
Removed the completed event emitter
Subscriber arrived
Removed the completed event emitter
Subscriber arrived
Removed the completed event emitter
Subscriber arrived
Removed the completed event emitter
Subscriber arrived
Removed the completed event emitter
Subscriber arrived

1 ответ

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

Один из способов убедиться в этом - установить retry поле для увеличения времени ожидания браузера (по умолчанию около 2-3 секунд). Другой способ - это иметь while (true) {} на стороне сервера, сразу после поступления запроса.

Также взгляните на этот пост о SSE.

Другие вопросы по тегам