HTML5医生网站在服务器发送的事件上有great write-up,但我会尽量在此提供一个(合理的)简短摘要。
服务器发送的事件在其核心是长时间运行的http连接,特殊的MIME类型(text/event-stream
)和提供了EventSource
API的用户代理。它们一起构成服务器和客户端之间的单向连接的基础,其中消息可以从服务器发送到。
在服务器端,它很简单。你真正需要做的是设置以下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")
})
在客户端,你只需要使用EventSource
API,正如你指出:
var source = new EventSource("/my-stream")
source.addEventListener("message", function(message) {
console.log(message.data)
})
就是这样,基本上是这样。
现在,实际上,这里实际发生的事情是,服务器和客户端通过相互契约保持连接。只要服务器认为合适,服务器就会保持连接处于活动状态。如果需要,它可能会终止连接并在客户端尝试连接时以204 No Content
响应。这将导致客户端停止尝试重新连接。我不确定是否有办法以客户端根本不会重新连接的方式结束连接,从而跳过客户端尝试重新连接一次。
如前所述,客户端将保持连接处于活动状态,并在丢弃时尝试重新连接。重新连接的算法在spec中指定,并且非常简单。
然而,我迄今为止几乎没有涉及的一个超级重要的位是mime类型。 MIME类型定义了连接中消息的格式。但是请注意,它并不指定消息的内容的格式,而仅仅是消息本身的结构。 mime类型非常简单。消息本质上是关键/值对的信息。密钥必须是一组预定义的一个:
- ID - 消息
- 数据的id - 实际数据
- 事件 - 事件类型
- 重试 - milleseconds用户代理应该等待在重试失败的连接之前
任何其他键应该被忽略。 (最后一个新行字符添加了冗长)
data: Hello, world!
\n
客户端将认为这是::消息然后通过使用两个换行字符分隔:\n\n
下面是一个有效的消息Hello, world!
。
由于是这样的:
data: Hello,
data: world!
\n
客户端将认为这是:Hello,\nworld!
。
这几乎总结了服务器发送的事件:长时间运行的非缓存http连接,MIME类型和简单的JavaScript API。
欲了解更多信息,我强烈建议您阅读specification。它很小,描述得非常好(尽管服务器端的要求可能总结得更好一些)。我强烈建议阅读它,以了解某些http状态代码的预期行为。
这对于客户端以及连接如何工作的细节非常有用,但是如果需要为数据库更改发送事件,我认为没有其他选择,只能在服务器上持续轮询数据库?我认为这是该操作的问题? 服务器端是否存在更高效的解决方案?显然,如果存在循环不断检查数据库更改,那么它在小型企业服务器上不会需要很多连接来降低速度。 –
只要服务器决定发送一个消息,客户端就会收到一条消息,它从不会轮询任何消息。服务器可以自行确定何时以及为什么发送消息。这可以通过使用轮询或任何符合法案的技术来实现服务器端。服务器上的连接可以合并,每条连接都可以发送一条消息,为您提供一种广播功能。因此,服务器可以是到数据库的单一连接,但可以向连接到服务器的大量客户端进行广播。我认为这个问题比这个更普遍。 –
重试:毫秒位 - 天才!保存我的皮肤! –