Рабочая группа WHATWG по доработке HTML предложила свой стандарт для получения событий с сервера в HTML 5.0. Для этого в нем предусмотрен специальный элемент event-source, который
реализован в Opera 9+, и предоставляет довольно удобный способ реализации событий с сервера.
Чтобы Ваш HTML проходил валидацию, да и вообще для удобства, лучше не ставить этот элемент в разметку, а манипулировать им при помощи javascript.
У элемента event-source есть атрибут src и метод addEventSource, которые говорят браузеру соединиться с указанным URL и принимать оттуда события. Например,
var el = document.createElement("event-source")
el.setAttribute('id', 'events')
el.setAttribute('src', 'server.php')
В ответ сервер должен сначала выразить готовность посылать события, отправив заголовок:
header("Content-Type: application/x-dom-event-stream");
Далее сервер присылает данные в специальном формате вида:
Event: sessionid data: RH7iaoUoq5ict7Z0lw3YaA Event: connect data: avvdw Event: connect data: test Event: ping data: pong
Т.е каждое событие это блок из Event:имя события\n и данных. Каждое поле данных пишется на отдельной строке и имеет имя, здесь: "data". После двоеточия ставится пробел. События разбиваются двойным переводом строки.
На момент написания, Opera 9.2 поддерживает только имя поля "data", хотя по спецификации можно указать любое.
Если поле с одним именем повторяется, то данные сливаются с переводом строки. Например, здесь поле data="1\n2":
Event: someEvent data: 1 data: 2
Так что многострочные данные тоже можно передавать через event source.
Серверный код для примера очень прост:
header("Content-Type: application/x-dom-event-stream");
ob_implicit_flush(true);
while (@ob_end_flush()) {}
for( $i = 1; $i <= 5; $i++ ) {
echo "Event: newMessage\n";
echo "data: $i\n";
echo "\n";
sleep(1);
}
Каждое событие вызывает обработчик, который указывается в браузере через addEventListener:
el.addEventListener('newMessage', function(event) { alert(event.data) }, false);
Браузер соединяется с сервером, как только в документе появляется event-source, и отсоединяется - как только event-source уходит из документа.
Клиентский код примера выше:
...
// создать элемент event-source
var el = document.createElement("event-source")
el.setAttribute('src', '/server_push/event_source.php')
el.setAttribute('id', 'event_source')
// добавить обработчик события newMessage
var newMessageHandler = function(event) {
var d = document.createElement('div')
d.innerHTML = "data: "+event.data
out.appendChild(d) // out - это div для вывода, определен ранее
}
el.addEventListener('newMessage', newMessageHandler, false);
// эта функция добавляет event-source в документ, браузер стучится на сервер
var startIt = function() {
document.body.appendChild(el)
}
// эта функция убирает event-source, браузер отключается от сервера
var stopIt = function() {
document.body.removeChild(el)
}
// запускаем, ограничиваем подключение 10 секундами
startIt()
setTimeout(stopIt, 10000)
В event-source принципиально не предусмотрена обработка ошибок. Единственный реальный способ ее сделать - регулярно слать ping-пакеты с сервера. Так, чтобы если клиент не получил ping-пакет вовремя - регистрируем задержку, прошел таймаут без пакетов - связь считаем нарушенной.
Никаких HTTP-заголовков, статусов с сервера, уведомлений об обрыве связи нет. В этом смысле Бесконечный IFrame удобнее.