每个应用程序是否只应该有一个EventSource对象?

15
当使用 服务器发送事件 时,客户端应该建立多个连接来接收它感兴趣的不同事件,还是应该有一个单一的连接,并且客户端通过一个单独的通道指示它所感兴趣的内容?在我看来,后者似乎更可取,尽管对于某些人来说,这可能会使客户端代码更加复杂。规范支持命名事件(与特定主题相关的事件),这表明服务器发送事件连接应该用作所有事件的单一通道。
以下代码说明了第一种情况,即启动多个服务器发送事件连接:
var EventSource eventSource1 = new EventSource("events/topic1");
eventSource1.addEventListener('topic1', topic1Listener, false);

var EventSource eventSource2 = new EventSource("events/topic2");
eventSource2.addEventListener('topic2', topic2Listener, false);

eventSource1会接收"topic1"事件,而eventSource2会接收"topic2"事件。虽然这很简单直观,但对于每个你感兴趣的主题都需要挂起GET请求,这也相当低效。另一种选择是以下方式:
var EventSource eventSource3 = new EventSource("/events?id=1234")
eventSource3.addEventListener('topic3', topic3Listener, false);
eventSource3.addEventListener('topic4', topic4Listener, false);

var subscription = new XMLHttpRequest();
subscription.open("PUT", "/events/topic3?id=1234", true);
subscription.send();

在这个例子中,将存在一个单一的EventSource,并且对特定事件的兴趣将通过使用Server-Sent Event连接的单独请求以及与id参数相关联的注册来指定。topic3Listener将接收"topic3"事件,而topic4Listener则不会。虽然需要稍微多写一些代码,但好处是只建立了一个连接,但事件仍然可以被识别和处理得不同。
网络上有很多示例展示了命名事件的使用,但似乎事件名称(或主题)是预先知道的,因此客户端无需向服务器注册兴趣(example)。虽然我还没有看到显示多个EventSource对象的示例,但我也没有看到一个示例,显示客户端使用单独的请求来注册对特定主题的兴趣,就像我上面所做的那样。我对规范的解释是,表明对某个主题(或事件名称)的兴趣完全取决于开发人员,并且可以使用客户端静态地知道它要接收的事件的名称或动态地告知服务器它有兴趣接收特定事件。

我很想听听其他人对这个话题的想法。注:我通常是Java开发人员,所以请原谅我的平庸JS代码.. :)


请勿在事件流中使用事件名称,而是可以监听“message”事件,在event.data中编码您的topicId和其他信息。 - 4esn0k
好的,但这意味着我需要在有效负载中编码这样的数据,当消息标识已经是规范数据帧的一部分时,这并没有太多意义。 - James Tyrrell
3
+1!非常好的问题。你最终做了什么?我也在考虑采用第二种方法。如果你能分享一下是否遇到过任何问题,我会很感激。 - 2020
1
@JamesTyrrell,你选择了哪个解决方案?你能否简要分享一下你的经验(或者最好在medium.com上写一篇文章)? - Sergii Stotskyi
2个回答

7
我个人认为,你应该为每个提供SSE的服务创建一个EventSource对象,并使用不同类型来发出消息。
但归根结底,这取决于消息类型的相似程度。例如,如果您有5种与用户相关的不同类型的消息,请创建一个名为“user”的EventSource并使用事件类型进行区分。
如果您有关于用户和三明治的两种事件类型,我建议将它们保留在不同的服务中,因此需要不同的EventSource
最好像拆分restful服务一样考虑拆分EventSources。如果您不会通过AJAX从同一服务获取两个内容,则可能不应该从同一EventSource获取它们。

那能扩展吗? - nilskp
从架构/结构的角度来看,我同意(出于你提到的所有原因),但连接限制是有成本的:你要么支持HTTP/2(包括强制端到端TLS),要么采用解决方法,比如为每个SSE服务使用子域名。由于各种原因,这两种方法都可能很繁琐,所以这是一种权衡。 - chris
@saml,如果在“EventSource” URL中传递参数,那该怎么办? - Rylan Schaeffer

1
作为对模糊和宽松的浏览器标准解释的回应,浏览器供应商不一致地实施了限制单个域名/端口允许的持久连接数量。由于每个事件接收器到异步上下文假定一个单一的持久连接分配只要那个接收器是打开的,因此必须严格限制EventSource监听器的数量,以避免超过不同的、供应商特定的限制。在实践中,这限制您在每个应用程序中使用约6个EventSource/异步上下文对。退化是优雅的(例如,额外的EventSource连接请求将仅等待直到有可用的插槽),但请记住必须有连接可用于检索页面资源、响应XHR等。 * W3C已发布关于持久连接的标准,其中包含语言“... 应该限制同时连接的数量...”这种语言意味着标准不是强制性的,因此供应商的合规性是可变的。http://www.w3.org/Protocols/rfc2616/rfc2616-sec8.html#sec8.1.4

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接