Server-Sent Events

admin

SSE — технология отправки уведомлений сервера к браузеру. Клиент как бы подключается к стриму обновлений и автоматически получает оповещения в случае новых событий.

Опрос сервера (polling и long polling)

Идея такова: AJAX-приложение проверяет новые данные на сервере. Клиент создает запрос и ждет ответа. Сервер возвращает ответ, даже если обновлений нет. Так что процесс создает дополнительную нагрузку на канал.

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

WebSocket или SSE

Технология Server-Sent Events открывает одностороннее соединение между сервером и клиентом, после чего сервер передает данные приложению, когда это потребуется (push notifications). Еще одно отличие — SSE обрабатываются непосредственно на стороне клиента, который только слушает канал.

WebSocket — другая технология обмена сообщениями между клиентом и сервером. Ее главное отличие в том, что связь двусторонняя, клиент принимает и отправляет сообщения.

Она подходит для продвинутых веб-приложений, игр, мессенджеров и т.д, где требуются связь в режиме реального времени.

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

Реализация на стороне клиента

API Server-Sent Events построен на интерфейсе EventSource. Поэтому для открытия нового соединения с сервером нужно создать объект EventSource. Он задает путь к скрипту, который создает события:

var evtSource = new EventSource("ssedemo.php");

# если скрипт лежит на другом домене, то так:

var evtSource = new EventSource("//api.example.com/ssedemo.php", { withCredentials: true } );

SSE на стороне клиента реализуется на JavaScript, скрипт сервера — на PHP, ASP, NodeJS или другом удобном языке

После инициализации соединения клиент может принимать сообщения:

evtSource.onmessage = function(e) {
  var newElement = document.createElement("li");
  
  newElement.innerHTML = "message: " + e.data;
  eventList.appendChild(newElement);
}

Принимает сообщения от сервера и добавляет текст сообщения в список HTML

А при помощи директивы addEventListener() также можно принимать события:

evtSource.addEventListener("ping", function(e) {
  var newElement = document.createElement("li");
  
  var obj = JSON.parse(e.data);
  newElement.innerHTML = "ping at " + obj.time;
  eventList.appendChild(newElement);
}, false);

Вызывается автоматически, когда сервер отправляет событие ping, клиент парсит JSON и выводит результат

Кроме собственных событий также используются стандартные ивенты:

  • onopen — при успешном открытии соединения;
  • onerror — в случае сбоя соединения;
  • onmessage — новое сообщение.

Простейший пример стандартных событий будет выглядеть так:

var eventSource = new EventSource('sse_demo');

eventSource.onopen = function(e) {
  console.log("Открыто соединение");
};

eventSource.onerror = function(e) {
  if (this.readyState == EventSource.CONNECTING) {
    console.log("Ошибка соединения, переподключение");
  } else {
    console.log("Состояние ошибки: " + this.readyState);
  }
};

eventSource.onmessage = function(e) {
  console.log("Сообщение: " + e.data);
};

Попытка переподключения в случае ошибки

Учтите, что событий может быть несколько.

Реализация на стороне сервера

Скрипт, который отправляет события, должен использовать MIME-тип text/event-stream. Каждое сообщение — простой текст, разделенный двумя символами новой линии (\n\n)(пустой строкой).

Наш бэкенд на PHP будет иметь вид:

date_default_timezone_set("America/New_York");
header("Content-Type: text/event-stream\n\n");

$counter = rand(1, 10);
while (1) {
  # Отправлять событие "ping" каждую секунду
  
  echo "event: ping\n";
  $curDate = date(DATE_ISO8601);
  echo 'data: {"time": "' . $curDate . '"}';
  echo "\n\n";
  
   $counter--;
  
  if (!$counter) {
    echo 'data: Время сообщения ' . $curDate . "\n\n";
    $counter = rand(1, 10);
  }
  
  ob_end_flush();
  flush();
  sleep(1);
}

Рандомно выводит сообщение с временной меткой

Самое главное

Используйте Server-Sent Events если нужна односторонняя связь между сервером и клиентом — вывод уведомлений, обновлений. Для более сложных задач подойдет WebSocket.

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

Останні статті

Обучение Power BI – какие онлайн курсы аналитики выбрать

Сегодня мы поговорим о том, как выбрать лучшие курсы Power BI в Украине, особенно для…

13.01.2024

Work.ua назвал самые конкурентные вакансии в IТ за 2023 год

В 2023 году во всех крупнейших регионах конкуренция за вакансию выросла на 5–12%. Не исключением…

08.12.2023

Украинская IT-рекрутерка создала бесплатный трекер поиска работы

Unicorn Hunter/Talent Manager Лина Калиш создала бесплатный трекер поиска работы в Notion, систематизирующий все этапы…

07.12.2023

Mate academy отправит работников в 10-дневный оплачиваемый отпуск

Edtech-стартап Mate academy принял решение отправить своих работников в десятидневный отпуск – с 25 декабря…

07.12.2023

Переписки, фото, история браузера: киевский программист зарабатывал на шпионаже

Служба безопасности Украины задержала в Киеве 46-летнего программиста, который за деньги устанавливал шпионские программы и…

07.12.2023

Как вырасти до сеньйора? Девелопер создал популярную подборку на Github

IT-специалист Джордан Катлер создал и выложил на Github подборку разнообразных ресурсов, которые помогут достичь уровня…

07.12.2023