Ответ 1
Измените эту строку
writer.write("data: "+ i +"\n\n");
к
writer.write("data: "+ i +"\r\n");
Кстати, ваш код будет иметь серьезную проблему с производительностью, потому что он будет удерживать поток до тех пор, пока не будут отправлены все события. Вместо этого используйте API асинхронной обработки. например.
protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
AsyncContext actx = req.startAsync();
actx.setTimeout(30*1000);
//save actx and use it when we need sent data to the client.
}
Затем мы можем использовать AsyncContext позже
//write some data to client when a certain event happens
actx.getResponse().getWriter().write("data: " + mydata + "\r\n");
actx.getResponse().getWriter().flush();
если все отправленные события можно закрыть,
actx.complete();
ОБНОВЛЕНИЕ 1:
Нам нужно закрыть источник событий в браузере, если мы не хотим, чтобы браузер снова подключался к серверу, когда сервер завершает ответ.
eventSource.close();
Возможно, помогает другой метод, а именно: мы установили довольно большое время повтора, но я не пробовал, например.
protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
AsyncContext actx = req.startAsync();
actx.getResponse().getWriter().write("retry: 36000000000\r\n"); // 10000 hours!
actx.getResponse().getWriter().flush();
//save actx and use it when we need sent data to the client.
}
ОБНОВЛЕНИЕ 2:
Я думаю, что Websocket, возможно, лучше для вашего дела.
ОБНОВЛЕНИЕ 3: (ответьте на вопросы)
- Что на самом деле происходит на сервере? В обычных сценариях tomcat создает поток для обработки каждого запроса. Что происходит сейчас?
Если используется NIO-коннектор, который по умолчанию используется в Tomcat 8.0.X, в течение всего цикла обработки HTTP-ввод-вывод о запросе не будет содержать поток. Если использовать BIO, поток будет удерживаться до завершения всего цикла обработки. Все потоки из пула потоков, tomcat не будет создавать поток для каждого запроса.
- Каков правильный способ обеспечить отправку потока событий только один раз в тот же сеанс соединения/браузера?
Do eventSource.close()
на стороне браузера - лучший выбор.
- Каков правильный способ обеспечения того, чтобы поток событий был закрыт, и на сервере не наложены дополнительные ресурсы?
Не забывайте вызывать AsyncContext.complete() на стороне сервера.
- Как различать запросы GET и POST. Почему он выбрал GET?
API EventSource в браузере поддерживает только запросы GET, но на стороне сервера нет такого ограничения. SSE в основном используется для получения данных событий с сервера. Если произойдет событие, браузер может получить его вовремя и не нужно создавать новый запрос для опроса. Если вам нужна полнодуплексная связь, попробуйте WebSocket в SSE.
- Слишком рано использовать SSE на Tomcat? Любые проблемы с производительностью?
Не должно быть проблем с производительностью, если мы используем NIO-соединитель и API асинхронной обработки. Я не знаю, является ли разъем Tomcat NIO зрелым или нет, но что-то никогда не будет известно, если мы не попробуем его.