服务器发送的事件:如何以跨浏览器的方式自动重新连接?
Server-sent events: How do you automatically reconnect in a cross-browser way?
我实现了一些代码来查询数据库的任何更改并发送事件。
这是我的 PHP 脚本的代码
header("Content-Type: text/event-stream");
header('Cache-Control: no-cache');
//****Some code here to query the database
echo "event: message\n";
echo "data: change_from_database \n";
echo "\n\n";
ob_flush();
flush();
我依靠浏览器在每次连接关闭时自动重新连接,所以我没有在我的服务器代码上实现任何循环。另外,我从this thread了解到实现无限循环有很多缺点。
所以客户端一切正常:每次连接关闭时浏览器重新连接,每次服务器发送一个事件时都会触发一个事件;好吧,除了不会重新连接的 Firefox (40.0.2)。我知道这不是因为我写了一些 JavaScript 错误检查代码来测试这个:
var evtSource = new EventSource("../sse.php");
evtSource.onerror = function(event){
var txt;
switch( event.target.readyState ){
case EventSource.CONNECTING:
txt = 'Reconnecting...';
break;
}
console.log(txt);
}
因此,每隔一秒,chrome 上的控制台就会记录 "Reconnecting"
。另一方面,Firefox 会重新连接一次,然后再也不会这样做。
如何编写代码才能在 Firefox 以及其他支持服务器发送事件但不自动重新连接的浏览器上运行?
您可以使用像这样的 polyfill https://github.com/Yaffle/EventSource,它将事件源功能添加到不受支持的浏览器。
运行 在我的网站上使用您的代码进行测试,在 Firefox 44.0.2 和 php 5.5 上一切正常。我在 Mozilla 开发网络上做了 运行 一些有趣的事情,尽管这表明你不一定能分辨出 Firefox past v22 上的错误消息是什么。也许您在错误检查中的 switch 语句让您失望了。这是 article 的 link。查看错误处理部分。
我的 php 代码与您的相同。以防万一我做了一些不同的事情,这是我的 html 代码。
<!DOCTYPE>
<html>
<head>
<title>SSE Test</title>
<meta charset="utf-8" />
<script>
var evtSource = new EventSource("sse.php");
evtSource.onerror = function(event){
var txt;
switch( event.target.readyState ){
case EventSource.CONNECTING:
txt = 'Reconnecting...';
break;
}
console.log(txt);
};
</script>
</head>
<body></body>
</html>
使用最新版本的 Firefox 浏览器 (44.0.2),您的代码可以完美运行。但是,您可以像这样在错误处理程序中重新初始化 EventSource
对象:
var evtSource = new EventSource("../sse.php");
var evtSourceErrorHandler = function(event){
var txt;
switch( event.target.readyState ){
case EventSource.CONNECTING:
txt = 'Reconnecting...';
break;
case EventSource.CLOSED:
txt = 'Reinitializing...';
evtSource = new EventSource("../sse.php");
evtSource.onerror = evtSourceErrorHandler;
break;
}
console.log(txt);
}
但我强烈不建议你这样做,因为你的代码没有利用保持连接的好处(正如你所写的,你知道无限循环)所以浏览器会进行简单的轮询(你可以看到这个在然后网络选项卡中)。我看不出有任何理由在 AJAX 上使用 SSE 而不保持永久连接,这显然很难用 PHP 维护。所以我假设在这种情况下使用简单的 AJAX 轮询。
我实现了一些代码来查询数据库的任何更改并发送事件。 这是我的 PHP 脚本的代码
header("Content-Type: text/event-stream");
header('Cache-Control: no-cache');
//****Some code here to query the database
echo "event: message\n";
echo "data: change_from_database \n";
echo "\n\n";
ob_flush();
flush();
我依靠浏览器在每次连接关闭时自动重新连接,所以我没有在我的服务器代码上实现任何循环。另外,我从this thread了解到实现无限循环有很多缺点。
所以客户端一切正常:每次连接关闭时浏览器重新连接,每次服务器发送一个事件时都会触发一个事件;好吧,除了不会重新连接的 Firefox (40.0.2)。我知道这不是因为我写了一些 JavaScript 错误检查代码来测试这个:
var evtSource = new EventSource("../sse.php");
evtSource.onerror = function(event){
var txt;
switch( event.target.readyState ){
case EventSource.CONNECTING:
txt = 'Reconnecting...';
break;
}
console.log(txt);
}
因此,每隔一秒,chrome 上的控制台就会记录 "Reconnecting"
。另一方面,Firefox 会重新连接一次,然后再也不会这样做。
如何编写代码才能在 Firefox 以及其他支持服务器发送事件但不自动重新连接的浏览器上运行?
您可以使用像这样的 polyfill https://github.com/Yaffle/EventSource,它将事件源功能添加到不受支持的浏览器。
运行 在我的网站上使用您的代码进行测试,在 Firefox 44.0.2 和 php 5.5 上一切正常。我在 Mozilla 开发网络上做了 运行 一些有趣的事情,尽管这表明你不一定能分辨出 Firefox past v22 上的错误消息是什么。也许您在错误检查中的 switch 语句让您失望了。这是 article 的 link。查看错误处理部分。
我的 php 代码与您的相同。以防万一我做了一些不同的事情,这是我的 html 代码。
<!DOCTYPE>
<html>
<head>
<title>SSE Test</title>
<meta charset="utf-8" />
<script>
var evtSource = new EventSource("sse.php");
evtSource.onerror = function(event){
var txt;
switch( event.target.readyState ){
case EventSource.CONNECTING:
txt = 'Reconnecting...';
break;
}
console.log(txt);
};
</script>
</head>
<body></body>
</html>
使用最新版本的 Firefox 浏览器 (44.0.2),您的代码可以完美运行。但是,您可以像这样在错误处理程序中重新初始化 EventSource
对象:
var evtSource = new EventSource("../sse.php");
var evtSourceErrorHandler = function(event){
var txt;
switch( event.target.readyState ){
case EventSource.CONNECTING:
txt = 'Reconnecting...';
break;
case EventSource.CLOSED:
txt = 'Reinitializing...';
evtSource = new EventSource("../sse.php");
evtSource.onerror = evtSourceErrorHandler;
break;
}
console.log(txt);
}
但我强烈不建议你这样做,因为你的代码没有利用保持连接的好处(正如你所写的,你知道无限循环)所以浏览器会进行简单的轮询(你可以看到这个在然后网络选项卡中)。我看不出有任何理由在 AJAX 上使用 SSE 而不保持永久连接,这显然很难用 PHP 维护。所以我假设在这种情况下使用简单的 AJAX 轮询。