В этом отношении новая технология 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. Доставляем показания серверных часов
Добавить комментарий