HTML5 医生网站有一篇关于服务器发送事件的精彩文章,但我也会尝试在此处提供一个(合理的)简短摘要。
服务器发送的事件的核心是长时间运行的 http 连接、特殊的 mime 类型 ( text/event-stream
) 和提供EventSource
API 的用户代理。这些共同构成了服务器和客户端之间单向连接的基础,其中消息可以从服务器发送到客户端。
在服务器端,它相当简单。您真正需要做的就是设置以下 http 标头:
Content-Type: text/event-stream
Cache-Control: no-cache
Connection: keep-alive
请务必使用代码200
而不是204
任何其他代码进行响应,因为这将导致兼容的用户代理断开连接。另外,请确保不要结束服务器端的连接。您现在可以自由地开始将消息推送到该连接。在 nodejs(使用 express)中,这可能类似于以下内容:
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")
})
在客户端上,您只需使用EventSource
API,如您所述:
var source = new EventSource("/my-stream")
source.addEventListener("message", function(message) {
console.log(message.data)
})
基本上就是这样。
现在,在实践中,这里实际发生的是服务器和客户端通过相互合同保持连接。只要它认为合适,服务器就会保持连接处于活动状态。如果它愿意,它可能会终止连接并204 No Content
在客户端下次尝试连接时做出响应。这将导致客户端停止尝试重新连接。我不确定是否有办法以告知客户端根本不重新连接的方式结束连接,从而跳过客户端尝试重新连接一次。
如前所述,客户端也将保持连接活动,并在断开连接时尝试重新连接。重新连接的算法在规范中指定,并且相当简单。
然而,到目前为止我几乎没有提到的一个超级重要的部分是 mime 类型。mime 类型定义了连接后消息的格式。但是请注意,它并没有规定消息内容的格式,只是规定了消息本身的结构。mime 类型非常简单。消息本质上是信息的键/值对。密钥必须是预定义的集合之一:
- id - 消息的 id
- data - 实际数据
- event - 事件类型
- retry - 用户代理在重试失败的连接之前应该等待的毫秒数
应忽略任何其他键。然后使用两个换行符分隔消息:\n\n
以下是一条有效消息:(为冗长添加了最后一个新行字符)
data: Hello, world!
\n
客户将看到它:Hello, world!
。
就像这样:
data: Hello,
data: world!
\n
客户将看到它:Hello,\nworld!
。
这几乎概括了服务器发送的事件是什么:一个长时间运行的非缓存 http 连接、一个 mime 类型和一个简单的 javascript API。
有关更多信息,我强烈建议阅读规范。它很小,并且很好地描述了事物(尽管可能会更好地总结服务器端的要求。)例如,我强烈建议您阅读它以了解具有某些 http 状态代码的预期行为。