Server Sent Events
Дата публикации: 09.01.2014
Server-sent events (SSE) — это технология, которая позволяет получать обновления веб — страницы с сервера в реальном режиме времени.
Таким образом, используя данную технологию, мы имеем возможность поддерживать постоянное обновление содержимого страницы.
Данная технология предоставляет много различных возможностей для html5 приложений, к примеру, если нужно постоянно обновлять информацию о ходе каких-то событий, выполнения длительных операций на стороне сервера, отображения информации о заказах, состоянии подключения к серверу, и так далее.
Server-Send Events vs. WebSockets
Существование такой технологии как WebSocket, которая предоставляет клиенту и серверу держать постоянное подключение, и работать в условиях приближенных к реальному времени, ставит под вопрос, в чем заключается преимущество и необходимость использования SSE технологии перед WebSockets?
Основная причина, почему SSE технология не столь известна как WebSockets, заключается в том, что ее появление было позже, чем WebSockets.
WebSockets — обеспечивает более богатый протокол для выполнения двунаправленной, полнодуплексной связи, и используется преимущественно для создания игр, чатов и всех тех приложений где скорость обмена между клиентом и сервером должна быть приведена максимально к режиму реального времени, а также в тех случаях, когда может понадобиться синхронизация между открытыми вкладками одного сайта, или одного сайта в разных браузерах.
Server-sent Events обеспечивает получение сообщений только со стороны сервера, и для работы этой технологии используется http протокол, в отличие от WebSockets.
Как это работает?
JavaScript API
Для начала работы необходимо определить источник получаемых сообщений. В качестве источника может выступать php скрипт.
var source = new EventSource(«demo.php»);
Далее для работы необходимо назначить обработчики событий. Объект EventSource поддерживает три стандартных типа событий, это:
| Обработчик события | Тип обработчика событий (addEventListener) |
|---|---|
| onopen | open |
| onmessage | message |
| onerror | error |
Так объект EventSource содержит такие свойства:
| Наименование | Значение |
|---|---|
| CONNECTING | Числовое значение — 0. Соединение не было установлено, или было закрыто и восстанавливается |
| OPEN | Числовое значение — 1. Соединение открыто и были привязаны события. |
| CLOSED | Числовое значение — 2. Соединения закрыто и попытка переподключения не выполняется. |
Кроме стандартных событий, можно организовать пользовательские события. Пользовательские события задаются определенной строкой ответа с сервера. Способы их определения будут описан ниже, при рассмотрении форматов сообщения которые формирует сервер.
Следующим шагом необходимо привязать события:
source.addEventListener("message", function(e) {
console.log(e.data);
}, false);
source.addEventListener("open", function(e) {
// Connection was opened.
}, false);
source.addEventListener("error", function(e) {
if (e.readyState === EventSource.CLOSED) {
// Connection was closed.
}
}, false);
Когда с сервера поступают новые сообщения, срабатывает событие onmessage. Данные которые были отправлены сервером, пишутся в атрибут события e.data.
В случае если связь с сервером разрывается, повторное подключение осуществляется примерно через 3 секунды. Интервал повторного подключения регулируется настройками сервера.
Формат ответа с сервера
Источник событий должен отвечать определенным стандартам для разграничения типа содержимого.
В нашем, demo.php для начала работы необходимо задать заголовок, который будет отдаваться с сервера:
header(«Content-Type: text/event-stream»); // необходимо для работы Server-sent Events
header(«Cache-Control: no-cache»); // рекомендуется делать для того, чтобы ответ не кэшировался.
Формат сообщения сервера должен содержать ключевое слово «data:», далее текст сообщения, и завершаться двумя символами «nn», пример:
data: Your message nn
В случае, если необходимо передать большое сообщение, тогда нужно в каждую строку с префиксом «data:» добавлять одни символ «n», а последней строке два «nn».
data: first linen
data: second linenn
В случае если необходимо отправить данные в формате JSON, можно использовать такой способ
data: {n
data: "msg": "hello world",n
data: "id": 12345n
data: }nn
source.addEventListener("message", function(e) {
var data = JSON.parse(e.data);
console.log(data.id, data.msg);
}, false);
В случае если необходимо сервером отправлять уникальные события, со стороны сервера в ответе с помощью ключевого слова «event:» задается название события.
event: eventNamen
data: {"name": "value"}nn
source.addEventListener("message", function(e) {
var data = JSON.parse(e.data);
console.log(data.msg);
}, false);
source.addEventListener("eventName", function(e) {
var data = JSON.parse(e.data);
console.log("User login:" + data.username);
}, false);
Пример:
serverEvents: (function () {
"use strict";
var controls = {},
handlers = {
open: function (event) {
console.log(event);
},
message: function (event) {
console.log(event);
},
error: function (event) {
console.log(event);
},
getId: function (event) {
console.log("id");
}
};
function getControls() {
controls.eventSource = new EventSource("php/server-events.php");
}
function addEvent() {
var eventSource = controls.eventSource;
eventSource.addEventListener("open", handlers.open, false);
eventSource.addEventListener("message", handlers.message, false);
eventSource.addEventListener("get_id", handlers.getId, false);
eventSource.addEventListener("error", handlers.error, false);
}
function init() {
getControls();
addEvent();
}
return {
init: function () {
init();
}
}
}())
Data.php
header("Content-Type: text/event-stream");
header("Content-Encoding: none; ");
header("Cache-Control: no-cache");
header("Access-Control-Allow-Origin: *");
$lastEventId = floatval(isset($_SERVER["HTTP_LAST_EVENT_ID"]) ? $_SERVER["HTTP_LAST_EVENT_ID"] : 0);
if ($lastEventId == 0) {
$lastEventId = floatval(isset($_GET["lastEventId"]) ? $_GET["lastEventId"] : 0);
}
ob_start();
echo ":" . str_repeat(" ", 2048) . "n"; // 2 kB padding for IE
echo "retry: 2000n";
// event-stream
$i = $lastEventId;
$c = $i + 100;
while (++$i
Так как данная технология на текущий момент не поддерживается в IE, можно воспользоваться библиотекой https://github.com/Yaffle/EventSource/, которая эмулирует работу объекта EventSources. Для работы библиотеки, ее нужно просто подключить.
Пример в действии:
http://jsfiddle.net/valsie/MCLds/1/
