Server-Sent Events — сервер тебя не оставит

В этом отношении новая технология Server-Sent Events, с одной стороны, является логическим развитием схемы Long Polling, с другой — эта схема организована принципиально по-другому.

В основе идеи Server-Sent Events лежит очень простая модель взаимодействия. Клиент, воплощенный веб-страницей, открытой в браузере, подписывается на определенные события сервера и, как только таковые случаются, сразу же получает данные, сгенерированные этим событием. Все и вправду настолько просто, что странно, что этого не придумали раньше. Впрочем, саму идею Server-Sent Events выдвинул девять лет назад Йен Хиксон (Ian Hickson, разработчик синтетического теста браузеров на соответствие веб-стандартам Acid, сейчас в Google), но воплощение в браузерах она нашла относительно недавно (в Firefox начиная с 6-й версии, Opera — с 10.6, Chrome — с 5-й, Safari — с 4-й).

Для реализации Server-Sent Events на стороне клиента необходимо задействовать новый объект — EventSource — и привязать к нему обработку ответа. Делается это следующим образом:

<script>

Var sse = new SventSource(‘Http://localhost/test_sse. php’); see. addEventListener(‘message’, function(e) { console. log(e. data);

}, false);

</script>

В данном случае события должны происходить в серверном сценарии test_sse. php, лежащем в корне нашего веб-сервера. Согласно спецификации Server-Sent Events, данные от сервера должны поступать с особым значением Content-type — text/event-stream.

Разумеется, просто указать Content-type мало, неплохо было бы, чтобы и данные этому типу соответствовали. Для этого сервер должен посылать их в следующем виде:

Id: 12345n retry: 100n data: first linen data: second linen data: last linen n

Поле id не является обязательным. Оно идентифицирует сообщение на случай сбоя связи. В случае подобной неприятности клиент вышлет специальный заголовок — Last-Event-ID, для возобновления взаимодействия с последнего доставленного сообщения. Поле retry содержит время переподключения (retry) в случае ошибок. Оно тоже не является обязательным. Сейчас мы напишем минимальную реальную реализацию скрипта test_sse. php для приведенного ранее клиентского кода:

<?php

Header(‘Content-Type: text/Svent-stream’);

$data = "server time: ".date("h:i:s", time());

Echo "data: ".$data. PHP_EOL; echo PHP_EOL;

Теперь, запустив клиентскую часть в браузере, мы увидим примерно то, что показано на рис. 85.

Обратите внимание — в серверном скрипте нам не понадобилось организовывать цикл или другую форму организации непрерывной

Рис. 85. Работа Server-Sent Events

Работы скрипта. Он и так будет опрашиваться непрерывно. Впрочем, это легко проверить, чуть дополнив клиентский код:

Sse. addEventListener(‘open’, function(e) { alert("open");

}, false);

Sse. addEventListener(‘error’, function(e) { if (e. eventPhase == EventSource. CLOSED) { alert("close")

}

}, false);

Если его запустить, станет очевидным то, что соединение с сервером все время прерывается и возобновляется. Это естественно — просто серверный цикл завершает работу, а объект EvenTSource вновь его перезапускает. Чтобы обеспечить настоящее взаимодействие с постоянно работающим скриптом, следует задействовать буферизацию на стороне сервера. Перепишем серверный скрипт, все-таки организовав цикл:

Header(‘Content-Type: text/тvent-stream’); header(‘Cache-Control: no-cache’); for ($i = 0; $i < ob_get_level(); $i++) { ob_end_flush();

}

Ob_implicit_flush(1); while(1) {

$data = "server time: ".$i. date("h:i:s", time()); echo "data: ".$data. PHP_EOL; echo PHP_EOL; sleep(1):

}

Теперь доставка ценной информации, а именно серверного времени, происходит в рамках одного соединения (рис. 86).

Рис. 86. Доставляем показания серверных часов

Добавить комментарий

Ваш e-mail не будет опубликован. Обязательные поля помечены *