使用while循环时未加载服务器端PHP事件页
我有一个名为handler.php的文件,它从文本文件中读取数据并将其推送到客户端页面 相关客户代码:使用while循环时未加载服务器端PHP事件页,php,server-side,server-sent-events,Php,Server Side,Server Sent Events,我有一个名为handler.php的文件,它从文本文件中读取数据并将其推送到客户端页面 相关客户代码: <script> if(typeof(EventSource) !== "undefined") { var source = new EventSource("handler.php"); source.onmessage = function(event) { var textarea = document.getElementById("sub
<script>
if(typeof(EventSource) !== "undefined") {
var source = new EventSource("handler.php");
source.onmessage = function(event) {
var textarea = document.getElementById("subtitles");
textarea.value += event.data;
textarea.scrollTop = textarea.scrollHeight;
};
} else {
document.getElementById("subtitles").value = "Server-sent events not supported.";
}
</script>
使用循环时,不会加载handler.php,因此不会向客户端发送任何数据。在Chrome开发者网络选项卡中,handler.php显示为“挂起”,然后显示为“取消”。文件本身保持锁定大约30秒
但是,如果我删除while循环(如下所示),则会加载handler.php,并且客户端确实会接收数据(仅接收一次,即使liveData.txt文件不断更新)
无循环的Handler.php:
$id = 0;
$event = 'event1';
$oldValue = null;
header('Content-Type: text/event-stream');
header('Cache-Control: no-cache');
header('X-Accel-Buffering: no');
try {
$data = file_get_contents('liveData.txt');
} catch(Exception $e) {
$data = $e->getMessage();
}
if ($oldValue !== $data) {
$oldValue = $data;
echo 'id: ' . $id++ . PHP_EOL;
echo 'event: ' . $event . PHP_EOL;
echo 'retry: 2000' . PHP_EOL;
echo 'data: ' . json_encode($data) . PHP_EOL;
echo PHP_EOL;
@ob_flush();
@flush();
}
我使用SSE是因为我只需要单向通信(所以WebSocket可能有点过头了),我真的不想使用轮询。如果我不能解决这个问题,我可能不得不这样做。我想你对网络的工作方式有问题。PHP代码不会在浏览器中运行——它只是创建一些web服务器通过网络传递给浏览器的东西 一旦从服务器加载了页面,就完成了。您需要实现一些轮询更改的功能 我这样做的一种方法是将页面放入一个循环中,该循环会刷新页面,因此每隔一秒左右就会使用新数据再次获取页面(但如果页面上有很多人,这可能会严重过载服务器)
唯一的另一种解决方案是使用推送技术和javascript框架,该框架可以进行推送并重新填充页面的相关部分,或者在计时器上使用javascript循环来提取数据。我认为您对web的工作方式有问题。PHP代码不会在浏览器中运行——它只是创建一些web服务器通过网络传递给浏览器的东西 一旦从服务器加载了页面,就完成了。您需要实现一些轮询更改的功能 我这样做的一种方法是将页面放入一个循环中,该循环会刷新页面,因此每隔一秒左右就会使用新数据再次获取页面(但如果页面上有很多人,这可能会严重过载服务器) 唯一的另一种解决方案是使用推送技术和javascript框架,该框架可以进行推送并重新填充页面的相关部分,或者在计时器上使用javascript循环来提取数据 使用循环时,不会加载handler.php,因此客户端不会加载 发送任何数据。在Chrome开发者网络选项卡中,handler.php是 显示为“待定”,然后显示为“已取消”。文件本身保持锁定状态 大约30秒 这是因为在30秒内没有响应时,Web服务器(Apache)或浏览器甚至PHP本身都会取消请求 因此,我猜刷新不起作用,请尝试在不使用
@
函数的情况下主动启动和结束缓冲区,以便在出现错误时获得线索
// Start output buffer
ob_start();
// Write content
echo '';
// Flush output buffer
ob_end_flush();
使用循环时,不会加载handler.php,因此客户端不会加载
发送任何数据。在Chrome开发者网络选项卡中,handler.php是
显示为“待定”,然后显示为“已取消”。文件本身保持锁定状态
大约30秒
这是因为在30秒内没有响应时,Web服务器(Apache)或浏览器甚至PHP本身都会取消请求
因此,我猜刷新不起作用,请尝试在不使用@
函数的情况下主动启动和结束缓冲区,以便在出现错误时获得线索
// Start output buffer
ob_start();
// Write content
echo '';
// Flush output buffer
ob_end_flush();
就我所知,SSE连接的客户端看起来很正常-尽管我将
var textarea…..
移动到onmessage
处理程序之外
更新:我应该仔细查看,但是要监视的事件是event1
,因此我们需要为该事件设置一个事件侦听器
<script>
if( typeof( EventSource ) !== "undefined" ) {
var url = 'handler.php'
var source = new EventSource( url );
var textarea = document.getElementById("subtitles");
source.addEventListener('event1', function(e){
textarea.value += e.data;
textarea.scrollTop = textarea.scrollHeight;
console.info(e.data);
},false );
} else {
document.getElementById("subtitles").value = "Server-sent events not supported.";
}
</script>
if(typeof(EventSource)!=“未定义”){
var url='handler.php'
var source=新事件源(url);
var textarea=document.getElementById(“字幕”);
source.addEventListener('event1',函数(e){
textarea.value+=e.data;
textarea.scrollTop=textarea.scrollHeight;
控制台信息(如数据);
},假);
}否则{
document.getElementById(“subtitles”).value=“不支持服务器发送的事件。”;
}
至于SSE服务器脚本,我倾向于使用这样的方法
<?php
/* make sure the script does not timeout */
set_time_limit( 0 );
ini_set('auto_detect_line_endings', 1);
ini_set('max_execution_time', '0');
/* start fresh */
ob_end_clean();
/* ultility function for sending SSE messages */
function sse( $evtname='sse', $data=null, $retry=1000 ){
if( !is_null( $data ) ){
echo "event:".$evtname."\r\n";
echo "retry:".$retry."\r\n";
echo "data:" . json_encode( $data, JSON_FORCE_OBJECT | JSON_HEX_QUOT | JSON_HEX_TAG | JSON_HEX_AMP | JSON_HEX_APOS );
echo "\r\n\r\n";
}
}
$id = 0;
$event = 'event1';
$oldValue = null;
header('Content-Type: text/event-stream');
header('Cache-Control: no-cache');
header('X-Accel-Buffering: no');
while( true ){
try {
$data = @file_get_contents( 'liveData.txt' );
} catch( Exception $e ) {
$data = $e->getMessage();
}
if( $oldValue !== $data ) {
/* data has changed or first iteration */
$oldValue = $data;
/* send the sse message */
sse( $event, $data );
/* make sure all buffers are cleansed */
if( @ob_get_level() > 0 ) for( $i=0; $i < @ob_get_level(); $i++ ) @ob_flush();
@flush();
}
/*
sleep each iteration regardless of whether the data has changed or not....
*/
sleep(1);
}
if( @ob_get_level() > 0 ) {
for( $i=0; $i < @ob_get_level(); $i++ ) @ob_flush();
@ob_end_clean();
}
?>
据我所知,SSE连接的客户端看起来很正常-尽管我将
var textarea….
移到了onmessage
处理程序之外
更新:我应该仔细查看,但是要监视的事件是event1
,因此我们需要为该事件设置一个事件侦听器
<script>
if( typeof( EventSource ) !== "undefined" ) {
var url = 'handler.php'
var source = new EventSource( url );
var textarea = document.getElementById("subtitles");
source.addEventListener('event1', function(e){
textarea.value += e.data;
textarea.scrollTop = textarea.scrollHeight;
console.info(e.data);
},false );
} else {
document.getElementById("subtitles").value = "Server-sent events not supported.";
}
</script>
if(typeof(EventSource)!=“未定义”){
var url='handler.php'
var source=新事件源(url);
var textarea=document.getElementById(“字幕”);
source.addEventListener('event1',函数(e){
textarea.value+=e.data;
textarea.scrollTop=textarea.scrollHeight;
控制台信息(如数据);
},假);
}否则{
document.getElementById(“subtitles”).value=“不支持服务器发送的事件。”;
}
至于SSE服务器脚本,我倾向于使用这样的方法
<?php
/* make sure the script does not timeout */
set_time_limit( 0 );
ini_set('auto_detect_line_endings', 1);
ini_set('max_execution_time', '0');
/* start fresh */
ob_end_clean();
/* ultility function for sending SSE messages */
function sse( $evtname='sse', $data=null, $retry=1000 ){
if( !is_null( $data ) ){
echo "event:".$evtname."\r\n";
echo "retry:".$retry."\r\n";
echo "data:" . json_encode( $data, JSON_FORCE_OBJECT | JSON_HEX_QUOT | JSON_HEX_TAG | JSON_HEX_AMP | JSON_HEX_APOS );
echo "\r\n\r\n";
}
}
$id = 0;
$event = 'event1';
$oldValue = null;
header('Content-Type: text/event-stream');
header('Cache-Control: no-cache');
header('X-Accel-Buffering: no');
while( true ){
try {
$data = @file_get_contents( 'liveData.txt' );
} catch( Exception $e ) {
$data = $e->getMessage();
}
if( $oldValue !== $data ) {
/* data has changed or first iteration */
$oldValue = $data;
/* send the sse message */
sse( $event, $data );
/* make sure all buffers are cleansed */
if( @ob_get_level() > 0 ) for( $i=0; $i < @ob_get_level(); $i++ ) @ob_flush();
@flush();
}
/*
sleep each iteration regardless of whether the data has changed or not....
*/
sleep(1);
}
if( @ob_get_level() > 0 ) {
for( $i=0; $i < @ob_get_level(); $i++ ) @ob_flush();
@ob_end_clean();
}
?>
(代表问题作者发布解决方案)
成功!在进行第n次调试时,我决定回到基础并重新开始。我放弃了循环,将PHP代码减少到最低限度,但保留了RamRaider提供的客户端代码。现在一切都非常好!通过使用retry值,我可以精确地指定推送数据的频率
PHP(服务器端):
Javascript(客户端):
if(typeof(EventSource)!=“未定义”){
var url='handler.php'
var source=新事件源(url);
var textarea=document.getElementById(“字幕”);
source.addEventListener('ev