ndh*_*ndh 7 javascript php html5 server-sent-events
我想从服务器到客户端定期发送更新.为此,我使用了服务器发送的事件.我正在粘贴以下代码:
客户端
<script>
if(typeof(EventSource)!="undefined")
{
var source=new EventSource("demo_see.php");
source.onmessage=function(event)
{
document.getElementById("result").innerHTML=event.data + "<br>";
}
}
else
{
document.getElementById("result").innerHTML="Sorry, your browser does not support server-sent events...";
}
</script>
</body>
</html>
Run Code Online (Sandbox Code Playgroud)
服务器端
<?php
header('Content-Type: text/event-stream');
header('Cache-Control: no-cache');
$x=rand(0,1000);
echo "data:{$x}\n\n";
flush();
?>
Run Code Online (Sandbox Code Playgroud)
代码工作正常但它会在每个代码中发送更新3 seconds
.我想以毫秒为单位发送更新.我尝试sleep(1)
之后flush()
,但它仅由1秒进一步增加的时间间隔.有没有人有一个想法我怎么能做到这一点?
另外,我可以使用服务器发送的事件发送图像吗?
Dro*_*dOS 12
正如上面的评论中所讨论的那样,在带有a sleep
或a 的无限循环中运行PHP脚本有usleep
两个原因
正确的做法是让您的PHP脚本响应事件流数据,然后像往常一样正常终止.retry
如果要控制浏览器何时再次尝试,请提供一个值(以毫秒为单位).这是一些示例代码
function yourEventData(&$retry)
{
//do your own stuff here and return your event data.
//You might want to return a $retry value (milliseconds)
//so the browser knows when to try again (not the default 3000 ms)
}
header('Content-Type: text/event-stream');
header('Cache-Control: no-cache');
header('Access-Control-Allow-Origin: *');//optional
$data = yourEventData($retry);
echo "data:{$str}\n\nretry:{$retry}\n\n";
Run Code Online (Sandbox Code Playgroud)
作为原始问题的答案,这有点晚,但为了完整性的利益:
以这种方式轮询服务器时获得的只是数据.之后你用它做什么完全取决于你.如果您希望将这些数据视为图像并更新网页中显示的图像,则只需执行此操作即可
document.getElementById("imageID").src = "data:image/png;base64," + Your event stream data;
Run Code Online (Sandbox Code Playgroud)
这些原则非常重要.我偶尔会忘记它retry
必须以毫秒为单位并最终返回,例如,retry:5\n\n
令我惊讶的是,它仍然有效.但是,我会毫不犹豫地使用SSE以100ms的间隔更新浏览器端图像.更典型的用法将是以下几行
retry
设置一个值,以便浏览器知道何时再次查看结果,而不是让用户等待没有反馈 - 并且冒着超时的危险.data{"code":-1}\n\n
因此浏览器侧代码可以优雅地处理该情况.还有其他使用场景 - 更新股票报价,新闻标题等.以100毫秒间隔更新图像感觉 - 纯粹是个人观点 - 就像滥用技术一样.
这种行为的原因(消息每3秒)在这里解释:
每次连接关闭后大约3秒钟,浏览器会尝试重新连接到源
因此,每100毫秒获取一次消息的一种方法是改变重新连接时间:(在PHP中)
echo "retry: 100\n\n";
Run Code Online (Sandbox Code Playgroud)
这不是很优雅,更好的方法是在PHP中无限循环,每次迭代将睡眠100毫秒.有很好的例子在这里,只是改变了sleep()
,以usleep()
支持毫秒:
while (1) {
$x=rand(0,1000);
echo "data:{$x}\n\n";
flush();
usleep(100000); //1000000 = 1 seconds
}
Run Code Online (Sandbox Code Playgroud)
我相信接受的答案可能会产生误导。尽管它正确地回答了问题(如何设置 1 秒间隔),但一般来说无限循环并不是一种糟糕的方法。
SSE 用于在实际存在更新时从服务器获取更新,这与 Ajax 轮询相反,Ajax 轮询在某些时间间隔内不断检查更新(即使没有更新)。这可以通过无限循环来完成,该循环使服务器端脚本始终运行,不断检查更新并仅在有更改时才回显它们。
以下说法不正确:
当该脚本仍在运行时,浏览器将看不到任何事件数据。
您可以在服务器上运行脚本,但仍然将更新发送到浏览器,而不是像这样结束脚本执行:
while (true) {
echo "data: test\n\n";
flush();
ob_flush();
sleep(1);
}
Run Code Online (Sandbox Code Playgroud)
通过发送重试参数而不无限循环来执行此操作将结束脚本,然后再次启动脚本,结束它,再次启动...这类似于 Ajax 轮询检查更新,即使没有更新,这不是 SSE 的方式打算工作。当然,在某些情况下,这种方法是合适的,就像已接受的答案中列出的那样(例如等待服务器创建 PDF 并在完成时通知客户端)。
使用无限循环技术将使脚本始终在服务器上运行,因此您应该小心处理大量用户,因为每个用户都有一个脚本实例,这可能会导致服务器过载。另一方面,即使在一些简单的场景中,您突然在网站上获得大量用户(没有 SSE),或者如果您使用 Web Sockets 而不是 SSE,也会发生同样的问题。一切都有其自身的局限性。
另一件需要注意的事情是你在循环中放入的内容。例如,我不建议将数据库查询放入每秒运行的循环中,因为这样您还会使数据库面临过载的风险。我建议在这种情况下使用某种缓存(Redis 甚至简单的文本文件)。
归档时间: |
|
查看次数: |
8677 次 |
最近记录: |