2011-10-03 44 views
25

所以我明白服务器发送的事件(EventSource)的概念:服务器发送的事件如何实际工作?

  • 客户端连接到一个端点通过EventSource
  • 客户端只是听从端点

事情发送的邮件我很困惑它是如何在服务器上工作的。我看过不同的例子,但是想到的是Mozilla的:http://hacks.mozilla.org/2011/06/a-wall-powered-by-eventsource-and-server-sent-events/

现在这可能只是一个坏例子,但它有点合理,服务器端将如何工作,据我了解:

  • 有新的变化在数据存储,如数据库
  • 的服务器端脚本民调数据存储每隔N个第二
  • 如果轮询脚本注意到一个变化,一个服务器发送的事件被触发到客户

这有道理吗?这是真的如何从一个准系统的角度来工作?

回答

40

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状态代码的预期行为。

+3

这对于客户端以及连接如何工作的细节非常有用,但是如果需要为数据库更改发送事件,我认为没有其他选择,只能在服务器上持续轮询数据库?我认为这是该操作的问题? 服务器端是否存在更高效的解决方案?显然,如果存在循环不断检查数据库更改,那么它在小型企业服务器上不会需要很多连接来降低速度。 –

+1

只要服务器决定发送一个消息,客户端就会收到一条消息,它从不会轮询任何消息。服务器可以自行确定何时以及为什么发送消息。这可以通过使用轮询或任何符合法案的技术来实现服务器端。服务器上的连接可以合并,每条连接都可以发送一条消息,为您提供一种广播功能。因此,服务器可以是到数据库的单一连接,但可以向连接到服务器的大量客户端进行广播。我认为这个问题比这个更普遍。 –

+2

重试:毫秒位 - 天才!保存我的皮肤! –

相关问题