我想从服务器向客户端发送定期更新。为此,我使用了服务器发送的事件。我正在粘贴以下代码:
客户端
获取服务器更新
<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>
服务器端
<?php
header('Content-Type: text/event-stream');
header('Cache-Control: no-cache');
$x=rand(0,1000);
echo "data:{$x}\n\n";
flush();
?>
该代码工作正常,但它每 3 秒
发送一次更新。我想以毫秒为单位发送更新。我在 flush()
之后尝试了 sleep(1)
但它只会将间隔进一步增加 1 秒。有谁知道我如何才能做到这一点?
另外,我可以使用服务器发送的事件发送图像吗?
最佳答案
正如上面评论中所讨论的那样,使用 sleep
或 usleep
在无限循环中运行 PHP 脚本是不正确的,原因有两个
- 当该脚本仍在运行时,浏览器将看不到任何事件数据(大概它会等待连接先关闭)。我记得 SSE 的早期浏览器实现允许这样做,但现在不再如此。
- 即使它确实在浏览器端工作,您仍然会面临 PHP 脚本运行时间过长的问题(直到 PHP.ini time_out 设置生效)。如果这种情况发生一两次就可以了。如果有 X 千个浏览器同时从您的服务器寻找相同的 SSE,这将导致您的服务器崩溃。
正确的做法是让您的 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";
作为对原始问题的回答,这有点但为了完整起见:
用这种方式轮询服务器得到的只是数据。之后你用它做什么完全取决于你。如果您想将这些数据视为图像并更新网页中显示的图像,您只需执行以下操作
document.getElementById("imageID").src = "data:image/png;base64," + Your event stream data;
关于这些原则。我有时忘记了 retry
必须以毫秒为单位并最终返回,例如 retry:5\n\n
令我惊讶的是,它仍然有效.但是,我会犹豫使用 SSE 以 100 毫秒的间隔更新浏览器端图像。更典型的用法是按照以下几行
- 用户在服务器上请求作业。该作业要么排队在其他作业之后,要么可能需要相当多的时间来执行(例如创建 PDF 或 Excel 电子表格并将其发回)
- 与其让用户在没有反馈的情况下等待 - 并冒着超时的风险 - 不如启动一个 SSE,告诉浏览器作业完成的预计到达时间,并设置一个
retry
值,这样浏览器知道何时再次查找结果。 - ETA 用于向用户提供一些反馈
- 在 ETA 结束时,浏览器将再次查看(浏览器会自动执行此操作,因此您无需执行任何操作)
- 如果由于某种原因作业没有被服务器完成,它应该在事件流中指出它返回,例如
data{"code":-1}\n\n
以便浏览器端代码可以优雅地处理这种情况。
还有其他使用场景 - 更新股票报价、新闻标题等。以 100 毫秒的间隔更新图像感觉 - 纯粹个人观点 - 就像滥用技术。
自从我发布这个答案到现在已经快 5 年了,它仍然经常被点赞。为了任何仍在使用它作为引用的人的利益——在我看来,在许多方面,SSE 是一种相当过时的技术。随着对 WebSockets 的广泛支持的出现,为什么还要费心做 SSE。除了其他任何事情之外,为每次浏览器端重试从浏览器设置和断开 HTTPS 连接的成本非常高。 WSS 协议(protocol)的效率要高得多。
如果你想实现 websockets 的阅读点
在我看来,PHP 不是一种处理 websockets 的好语言,而且 Ratchet 远非易于设置。 Nginx/NChan 路线要容易得多。
关于javascript - 在 HTML5 服务器发送事件中设置时间间隔,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/16315137/