пользователей: 30398
предметов: 12406
вопросов: 234839
Конспект-online
РЕГИСТРАЦИЯ ЭКСКУРСИЯ

События на стороне сервера

  1. События на стороне сервера

Server Side Events -- события с сервера

Сразу заметим, что на текущий момент этот способ поддерживают все современные браузеры, кроме IE.

Современный стандарт Server-Sent Events позволяет браузеру создавать специальный объект EventSource, который сам обеспечивает соединение с сервером, делает пересоединение в случае обрыва и генерирует события при поступлении данных.

Он, по дизайну, может меньше, чем WebSocket’ы.

С другой стороны, Server Side Events проще в реализации, работают по обычному протоколу HTTP и сразу поддерживают ряд возможностей, которые для WebSocket ещё надо реализовать.

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

Получение сообщений

При создании объекта new EventSource(src) браузер автоматически подключается к адресу src и начинает получать с него события:

var eventSource = new EventSource("/events/subscribe");

 
eventSource.onmessage = function(e) {
  console.log("Пришло сообщение: " + e.data);
};

Чтобы соединение успешно открылось, сервер должен ответить с заголовком Content-Type: text/event-stream, а затем оставить соединение висящим и писать в него сообщения в специальном формате:

data: Сообщение 1

 
data: Сообщение 2

 
data: Сообщение 3
data: из двух строк

·       Каждое сообщение пишется после data:. Если после двоеточия есть пробел, то он игнорируется.

·       Сообщения разделяются двумя строками \n\n.

·       Если нужно переслать перевод строки, то сообщение разделяется. Каждая следующая строка пересылается отдельным data:.

В частности, две последние строки в примере выше составляют одно сообщение: "Сообщение 3\nиз двух строк".

Здесь все очень просто и удобно, кроме разделения сообщения при переводе строки. Но, если подумать – это не так уж страшно: на практике сложные сообщения обычно передаются в формате JSON. А перевод строки в нём кодируется как \n.

Соответственно, многострочные данные будут пересылаться так:

data: {"user":"Вася","message":"Сообщение 3\n из двух строк"}

…То есть, строка data: будет одна, и никаких проблем с разделением сообщения нет.

Восстановление соединения

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

Это очень удобно, никакой другой транспорт не обладает такой встроенной способностью.

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

При любом закрытии соединения, в том числе если сервер ответит на запрос и закроет соединение сам – браузер через короткое время повторит свой запрос.

Есть лишь два способа, которыми сервер может «отшить» надоедливый EventSource:

·       Ответить со статусом не 200.

·       Ответить с Content-Type, не совпадающим с text/event-stream.

Между попытками возобновить соединение будет пауза, начальное значение которой зависит от браузера (1-3 секунды) и может быть изменено сервером через указание retry: в ответе:

retry: 15000
data: Поставлена задержка 15 секунд

Браузер, со своей стороны, может закрыть соединение вызовом close():

var eventSource = new EventSource(...);

 
eventSource.close();

При этом дальнейших попыток соединения не будет. Открыть обратно этот объект тоже нельзя, можно создать новый EventSource.

Идентификатор id

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

Сервер может указать его в ответе:

data: Сообщение 1
id: 1

 
data: Сообщение 2
id: 2

 
data: Сообщение 3
data: из двух строк
id: 3

При получении id: браузер:

·       Устанавливает свойство eventSource.lastEventId в его значение.

·       При пересоединении пошлёт заголовок Last-Event-ID с этим id, так что сервер сможет переслать последующие, пропущенные, сообщения.

Обратим внимание: id шлётся не перед сообщением, а после него, чтобы обновление lastEventIdпроизошло, когда браузер всё уже точно получил.

Статус соединения readyState

У объекта EventSource есть свойство readyState, которое содержит одно из значений (выдержка из стандарта):

const unsigned short CONNECTING = 0; // в процессе (пере-)соединения
const unsigned short OPEN = 1;       // соединение установлено
const unsigned short CLOSED = 2;     // соединение закрыто

При создании объекта и при разрыве оно автоматически равно CONNECTING.

События

Событий всего три:

·       onmessage – пришло сообщение, доступно как event.data

·       onopen – при успешном установлении соединения

·       onerror – при ошибке соединения.

Например:

var eventSource = new EventSource('digits');

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

Своё имя события: event

По умолчанию на события срабатывает обработчик onmessage, но можно сделать и свои события. Для этого сервер должен указать перед событием его имя после event:.

Например:

event: join
data: Вася

 
data: Привет

 
event: leave
data: Вася

Сообщение по умолчанию имеет имя message.

Для обработки своих имён событий необходимо ставить обработчик при помощи addEventListener.

Пример кода для обработки:

eventSource.addEventListener('join', function(e) {
  alert( 'Пришёл ' + e.data );
});

 
eventSource.addEventListener('message', function(e) {
  alert( 'Сообщение ' + e.data );
});

 
eventSource.addEventListener('leave', function(e) {
  alert( 'Ушёл ' + e.data );
});

Итого

Объект EventSource предназначен для передачи текстовых сообщений с сервера, используя обычный протокол HTTP.

Он предлагает не только передачу сообщений, но и встроенную поддержку важных вспомогательных функций:

·       События event.

·       Автоматическое пересоединение, с настраиваемой задержкой retry.

·       Проверка текущего состояния подключения по readyState.

·       Идентификаторы сообщений id для точного возобновления потока данных, последний полученный идентификатор передаётся в заголовке Last-Event-ID.

·       Кросс-доменность CORS.

Этот набор функций делает EventSource достойной альтернативой WebSocket, которые хоть и потенциально мощнее, но требуют реализации всех этих функций на клиенте и сервере, поверх протокола.

Поддержка – все браузеры, кроме IE.

·       Синтаксис:

var source = new EventSource(src[, credentials]); // src - адрес с любого домена

Второй необязательный аргумент, если указан в виде { withCredentials: true }, инициирует отправку Cookie и данных авторизации при кросс-доменных запросах.

Безопасность при кросс-доменных запросах обеспечивается аналогично XMLHttpRequest.

·       Свойства объекта:

readyState

Текущее состояние соединения, одно из EventSource.CONNECTING (=0)EventSource.OPEN (=1)или EventSource.CLOSED (=2).

lastEventId

Последнее полученное id, если есть. При возобновлении соединения браузер указывает это значение в заголовке Last-Event-ID.

urlwithCredentials

Параметры, переданные при создании объекта. Менять их нельзя.

·       Методы:

close()

Закрывает соединение.

·       События:

onmessage

При сообщении, данные – в event.data.

onopen

При установлении соединения.

onerror

При ошибке, в том числе – закрытии соединения по инициативе сервера.

Эти события можно ставить напрямую через свойство: source.onmessage = ....

Если сервер присылает имя события в event:, то такие события нужно обрабатывать через addEventListener.

·       Формат ответа сервера:

Сервер присылает пустые строки, либо строки, начинающиеся с:

o   data: – сообщение, несколько таких строк подряд склеиваются и образуют одно сообщение.

o   id: – обновляет lastEventId.

o   retry: – указывает паузу между пересоединениями, в миллисекундах. JavaScript не может указать это значение, только сервер.

o   event: – имя события, должен быть перед data:.

 

 


22.06.2017; 21:52
хиты: 93
рейтинг:0
для добавления комментариев необходимо авторизироваться.
  Copyright © 2013-2024. All Rights Reserved. помощь