简体   繁体   English

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

[英]Browsers are not responding to Server-Sent Events until server closes connection

On my Express/Node server, I set the content type to text/event-stream : 在我的Express / Node服务器上,我将内容类型设置为text/event-stream

res.writeHead(200, {
  'Content-Type': 'text/event-stream'
});

Then, as a series of callbacks fire, I write data messages to the stream and follow it with two new lines: 然后,当一系列回调触发时,我将数据消息写入流并使用两个新行跟随它:

res.write('data: ' + JSON.stringify(data) + '\n\n');

If I add logging on the server side or if I just hit the URL with curl , I can see that data messages are being written over a few seconds. 如果我在服务器端添加日志记录,或者我只是使用curl点击URL,我可以看到数据消息正在写入几秒钟。

However, when I try to use these data messages in a web page, nothing happens. 但是,当我尝试在网页中使用这些数据消息时,没有任何反应。 (I'm testing on Chrome, Firefox, and Safari all on a Mac.) Here's what the Web page looks like: (我在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>

If I add a final callback on the server side that closes the connection (using res.end() ) then the browsers respond to the data messages all at once, and only once res.end() has happened. 如果我在服务器端添加一个关闭连接的最终回调(使用res.end() ),那么浏览器会立即响应所有数据消息,并且只发生一次res.end() Which would seem to defeat the purpose of using Server-Sent Events. 这似乎打败了使用Server-Sent Events的目的。

What do I need to change (short of giving up and switching to XHR polling) to have the browsers respond to the Server-Sent Events as they arrive (which would seem to be exactly the purpose and use case for Server-Sent Events)? 我需要改变什么(没有放弃并切换到XHR轮询)让浏览器在服务器发送事件到达时响应它们(这似乎是服务器发送事件的目的和用例)?

(Test page demonstrating the problem was available but now that this problem has been resolved, I've removed it.) (显示问题的测试页面已经可用但是现在已经解决了这个问题,我已将其删除了。)

It looks like you have some middleware that is doing compression; 看起来你有一些正在进行压缩的中间件; and in doing this, it is buffering until you complete the response. 并且在执行此操作时,它将缓冲,直到您完成响应。 You can see this with curl: 你可以用curl看到这个:

First, bare GET: 首先,裸GET:

curl <url>

Next, add an Accept-Encoding header (similar to what your browser is using): 接下来,添加一个Accept-Encoding标头(类似于您的浏览器使用的标头):

curl <url>  -H 'Accept-Encoding: gzip,deflate,sdch' --compressed

Note that --compressed just tells curl to decompress it for you. 请注意--compressed只是告诉curl为你解压缩它。

You'll notice that you see the expected behavior on the first one, but not the second. 您会注意到您在第一个上看到了预期的行为,但没有看到第二个上的预期行为。 This makes it clear that it is related to the compression. 这清楚地表明它与压缩有关。 I suggest turning off compression for that route, or finding a smarter middleware that knows how to compress each frame. 我建议关闭该路由的压缩,或者找一个知道如何压缩每个帧的更智能的中间件。

It works fine for me in Chrome. 它在Chrome中适用于我。 Here's my test code: 这是我的测试代码:

sse.js: sse.js:

var app = require('express')();

app.get('/', function(req, res) {
  res.sendFile(__dirname + '/sse.htm');
});
app.get('/events', function(req, res) {
  var counter = 0;
  res.writeHead(200, { 'Content-Type': 'text/event-stream' });
  setInterval(function() {
    res.write('data: ' + JSON.stringify({name: 'foo' + (counter++) }) + '\n\n');
  }, 1000);
  res.write('data: ' + JSON.stringify({name: 'foo' + (counter++) }) + '\n\n');
});

app.listen(8000);

sse.htm: sse.htm:

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

  <script>
    var source = new EventSource('/events');
    source.onmessage = function(e) {
      document.body.innerHTML += JSON.parse(e.data).name + '<br />';
    };
    source.onerror = function(e) {
      source.close();
    };
  </script>
</body>
</html>

this produces the following output: 这会产生以下输出:

foo0
// one second later
foo1
// two seconds later
foo2
// three seconds later
foo3
// etc.

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM