Ответ 1
Сайт доктора HTML5 имеет отличную запись на событиях, отправленных сервером, но я постараюсь предоставить (разумно) короткий здесь также.
События, отправленные сервером, по сути являются длинным HTTP-соединением, специальным типом mime (text/event-stream
) и пользовательским агентом, который предоставляет API EventSource
. Вместе они создают основу однонаправленной связи между сервером и клиентом, где сообщения могут отправляться с сервера на клиент.
На стороне сервера это довольно просто. Все, что вам действительно нужно сделать, это установить следующие заголовки http:
Content-Type: text/event-stream
Cache-Control: no-cache
Connection: keep-alive
Обязательно ответьте кодом 200
, а не 204
или любым другим кодом, так как это приведет к отключению совместимых пользовательских агентов. Кроме того, не завершайте соединение на стороне сервера. Теперь вы можете начать отталкивать сообщения по этому соединению. В nodejs (с помощью выражения) это может выглядеть примерно так:
app.get("/my-stream", function(req, res) {
res.status(200)
.set({ "content-type" : "text/event-stream"
, "cache-control" : "no-cache"
, "connection" : "keep-alive"
})
res.write("data: Hello, world!\n\n")
})
На клиенте вы просто используете API EventSource
, как вы отметили:
var source = new EventSource("/my-stream")
source.addEventListener("message", function(message) {
console.log(message.data)
})
И что это, в основном.
Теперь, на практике, на самом деле происходит то, что соединение поддерживается сервером и клиентом посредством взаимного договора. Сервер будет поддерживать соединение до тех пор, пока он сочтет нужным. Если он захочет, он может завершить соединение и ответить с помощью 204 No Content
в следующий раз, когда клиент попытается подключиться. Это заставит клиента перестать пытаться снова подключиться. Я не уверен, есть ли способ завершить соединение таким образом, что клиенту будет предложено не пересоединяться вообще, тем самым пропуская клиент, пытающийся повторно подключиться.
Как упоминалось, клиент также сохранит соединение и попытается снова подключиться, если он будет удален. Алгоритм повторного подключения указан в spec и довольно прямолинейный.
Один очень важный бит, который я до сих пор едва затронул, это тип mime. Тип mime определяет формат сообщения, идущего вниз по соединению. Обратите внимание, однако, что это не диктует формат содержимого сообщений, а только структуру самих сообщений. Тип мим очень прост. Сообщения - это, по сути, пара ключей/значений информации. Ключ должен быть одним из предопределенных множеств:
- id - идентификатор сообщения
- данные - фактические данные
- событие - тип события
- retry - миллисекунды, которые должен ожидать пользовательский агент перед повторной попыткой неудачного подключения.
Любые другие клавиши следует игнорировать. Сообщения затем разделяются с использованием двух символов новой строки: \n\n
Ниже приведено правильное сообщение: (последние новые символы строки добавлены для подробностей)
data: Hello, world!
\n
Клиент увидит это как: Hello, world!
.
Как это:
data: Hello,
data: world!
\n
Клиент увидит это как: Hello,\nworld!
.
Это в значительной степени суммирует, какие события, отправленные сервером: долгое не кэшированное http-соединение, тип mime и простой javascript API.
Для получения дополнительной информации я настоятельно рекомендую прочитать спецификацию . Он очень мал и очень хорошо описывает вещи (хотя требования серверной части можно свести к лучшему.) Я настоятельно рекомендую прочитать его для ожидаемого поведения с определенными кодами статуса http, например.