在服务器关闭连接之前,浏览器不会响应服务器发送的事件

Tro*_*ott 5 javascript node.js express server-sent-events

在我的 Express/Node 服务器上,我将内容类型设置为text/event-stream

res.writeHead(200, {
  'Content-Type': 'text/event-stream'
});
Run Code Online (Sandbox Code Playgroud)

然后,当一系列回调触发时,我将数据消息写入流并在其后添加两行新行:

res.write('data: ' + JSON.stringify(data) + '\n\n');
Run Code Online (Sandbox Code Playgroud)

如果我在服务器端添加日志记录,或者如果我只是用 来点击 URL curl,我可以看到数据消息在几秒钟内被写入。

但是,当我尝试在网页中使用这些数据消息时,没有任何反应。(我正在 Mac 上的 Chrome、Firefox 和 Safari 上进行测试。)这是网页的样子:

<!DOCTYPE html>
<html>
<head>
  <meta charset="utf-8" />
  <title>Testing</title>
</head>
<body>
  <h1>Server-Sent Events Test</h1>

  <script>
    var source = new EventSource('/library/search?q=medicine&async');
    source.onmessage = function(e) {
      document.body.innerHTML += JSON.parse(e.data).name + '<br>';
    };
  </script>
</body>
</html>
Run Code Online (Sandbox Code Playgroud)

如果我在服务器端添加一个关闭连接的最终回调(使用res.end()),那么浏览器会立即响应所有数据消息,并且只res.end()发生一次。这似乎违背了使用服务器发送事件的目的。

我需要改变什么(除了放弃并切换到 XHR 轮询之外)才能让浏览器在服务器发送事件到达时做出响应(这似乎正是服务器发送事件的目的和用例)?

(演示该问题的测试页面可用,但现在此问题已解决,我已将其删除。)

Aar*_*our 5

看起来您有一些正在进行压缩的中间件;在这样做时,它会一直缓冲,直到您完成响应。你可以用 curl 看到这一点:

首先,裸GET:

curl <url>
Run Code Online (Sandbox Code Playgroud)

接下来,添加一个Accept-Encoding标题(类似于您的浏览器使用的内容):

curl <url>  -H 'Accept-Encoding: gzip,deflate,sdch' --compressed
Run Code Online (Sandbox Code Playgroud)

请注意,这--compressed只是告诉curl您为您解压缩它。

您会注意到您在第一个上看到了预期的行为,但在第二个上没有看到。这清楚地表明它与压缩有关。我建议关闭该路由的压缩,或者找到一个知道如何压缩每个帧的更智能的中间件。