服务器发送的事件实际上是如何工作的? [英] How do server-sent events actually work?

查看:44
本文介绍了服务器发送的事件实际上是如何工作的?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

所以我理解了服务器发送事件的概念(EventSource):

So I understand the concept of server-sent events (EventSource):

  • 客户端通过 EventSource
  • 连接到端点
  • 客户端只监听从端点发送的消息

令我感到困惑的是它在服务器上的工作方式.我看过不同的例子,但我想到的是 Mozilla 的:http://hacks.mozilla.org/2011/06/a-wall-powered-by-eventsource-and-server-sent-events/

The thing I'm confused about is how it works on the server. I've had a look at different examples, but the one that comes to mind is Mozilla's: http://hacks.mozilla.org/2011/06/a-wall-powered-by-eventsource-and-server-sent-events/

现在这可能只是一个不好的例子,但据我了解,服务器端的工作方式是有道理的:

Now this may be just a bad example, but it kinda makes sense how the server side would work, as I understand it:

  • 数据存储中的某些更改,例如数据库
  • 服务器端脚本每 N 秒轮询一次数据存储
  • 如果轮询脚本注意到更改,则会向客户端触发服务器发送的事件

有意义吗?从准系统的角度来看,它真的是这样工作的吗?

Does that make sense? Is that really how it works from a barebones perspective?

推荐答案

HTML5 医生网站有一个 很棒 关于服务器发送的事件,但我也会尝试在此处提供(合理的)简短摘要.

The HTML5 doctor site has a great write-up on server-sent events, but I'll try to provide a (reasonably) short summary here as well.

服务器发送的事件的核心是一个长时间运行的 http 连接、一个特殊的 mime 类型 (text/event-stream) 和一个提供 EventSource 的用户代理代码> API.这些共同构成了服务器和客户端之间的单向连接的基础,其中消息可以从服务器发送到客户端.

Server-sent events are, at its core, a long running http connection, a special mime type (text/event-stream) and a user agent that provides the EventSource API. Together, these make the foundation of a unidirectional connection between a server and a client, where messages can be sent from server to client.

在服务器端,它相当简单.您真正需要做的就是设置以下 http 标头:

On the server side, it's rather simple. All you really need to do is set the following http headers:

Content-Type: text/event-stream
Cache-Control: no-cache
Connection: keep-alive

请务必使用代码 200 而不是 204 或任何其他代码响应,因为这会导致兼容的用户代理断开连接.另外,请确保不要在服务器端结束连接.您现在可以自由地开始通过该连接推送消息.在 nodejs(使用 express)中,这可能类似于以下内容:

Be sure to respond with the code 200 and not 204 or any other code, as this will cause compliant user agents to disconnect. Also, make sure to not end the connection on the server side. You are now free to start pushing messages down that connection. In nodejs (using express), this might look something like the following:

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,正如您所指出的:

On the client, you just use the EventSource API, as you noted:

var source = new EventSource("/my-stream")
source.addEventListener("message", function(message) {
    console.log(message.data)
})

基本上就是这样.

现在,在实践中,这里实际发生的是服务器和客户端通过相互契约来保持连接.只要它认为合适,服务器就会保持连接处于活动状态.如果它愿意,它可能会终止连接并在下次客户端尝试连接时以 204 No Content 响应.这将导致客户端停止尝试重新连接.我不确定是否有办法终止连接,告知客户端根本不要重新连接,从而跳过客户端尝试重新连接一次.

Now, in practice, what actually happens here is that the connection is kept alive by the server and the client by means of a mutual contract. The server will keep the connection alive for as long as it sees fit. Should it want to, it may terminate the connection and respond with a 204 No Content next time the client tries to connect. This will cause the client to stop trying to reconnect. I'm not sure if there's a way to end the connection in a way that the client is told not to reconnect at all, thereby skipping the client trying to reconnect once.

如前所述,客户端也会保持连接处于活动状态,并在连接断开时尝试重新连接.重新连接的算法在 规范 中指定,并且相当简单前进.

As mentioned client will keep the connection alive as well, and try to reconnect if it is dropped. The algorithm to reconnect is specified in the spec, and is fairly straight forward.

到目前为止我几乎没有涉及的一个非常重要的部分是 mime 类型.mime 类型定义了从连接传来的消息的格式.但是请注意,它并没有规定消息的内容 的格式,而只是规定了消息本身的结构.mime 类型非常简单.消息本质上是信息的键/值对.密钥必须是预定义的集合之一:

One super important bit that I've so far barely touched on however is the mime type. The mime type defines the format of the message coming down the connecting. Note however that it doesn't dictate the format of the contents of the messages, just the structure of the messages themselves. The mime type is extremely straight forward. Messages are essentially key/value pairs of information. The key must be one of a predefined set:

  • id - 消息的 ID
  • data - 实际数据
  • 事件 - 事件类型
  • retry - 用户代理在重试失败的连接之前应等待的毫秒数

应该忽略任何其他键.然后使用两个换行符分隔消息:\n\n

Any other keys should be ignored. Messages are then delimited by the use of two newline characters: \n\n

以下是一条有效的消息:(为详细起见添加了最后一个新行字符)

The following is a valid message: (last new line characters added for verbosity)

data: Hello, world!
\n

客户端会看到:Hello, world!.

是这样的:

data: Hello,
data: world!
\n

客户端会看到:Hello,\nworld!.

这几乎总结了服务器发送的事件:长时间运行的非缓存 http 连接、mime 类型和简单的 javascript API.

That pretty much sums up what server-sent events are: a long running non-cached http connection, a mime type and a simple javascript API.

有关详细信息,我强烈建议您阅读规范.它很小并且很好地描述了事情(尽管服务器端的要求可能会更好地概括.)我强烈建议阅读它以了解具有某些 http 状态代码的预期行为,例如.

For more information, I strongly suggest reading the specification. It's small and describes things very well (although the requirements of the server side could possibly be summarized a bit better.) I highly suggest reading it for the expected behavior with certain http status codes, for instance.

这篇关于服务器发送的事件实际上是如何工作的?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆