[英]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.