使用while循环时服务器端PHP事件页面未加载 [英] Server-side PHP event page not loading when using while loop

查看:65
本文介绍了使用while循环时服务器端PHP事件页面未加载的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个名为 handler.php 的文件,它从文本文件中读取数据并将其推送到客户端页面.

I have a file named handler.php which reads data from a text file and pushes it to a client page.

相关客户端代码:

<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 代码:

Handler.php code:

$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) {
        $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();
        sleep(1);  
        }

  }

使用循环时,handler.php 永远不会加载,因此客户端不会收到任何数据.在 Chrome 开发者网络选项卡中,handler.php 显示为Pending",然后显示为Cancelled".文件本身会保持锁定状态约 30 秒.

When using the loop, handler.php is never loaded so the client doesn't get sent any data. In the Chrome developer network tab, handler.php is shown as "Pending" and then "Cancelled". The file itself stays locked for around 30 seconds.

然而,如果我删除 while 循环(如下所示),handler.php 被加载并且客户端确实接收数据(只有一次,即使 liveData.txt 文件不断更新).

However, if I remove the while loop (as shown below), handler.php is loaded and the client does receive data (only once, even though the liveData.txt file is constantly updated).

没有循环的Handler.php:

Handler.php without loop:

$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,因为我只需要单向通信(所以 websockets 可能有点矫枉过正)而且我真的不想使用轮询.如果我不能解决这个问题,我可能不得不这样做.

I'm using SSE as I only need one-way communication (so websockets are probably overkill) and I really don't want to use polling. If I can't sort this out, I may have to.

推荐答案

据我所知,SSE 连接的客户端看起来不错 - 尽管我移动了 var textarea.....onmessage 处理程序之外.

The client side of the SSE connection looks OK as far as I can tell - though I moved the var textarea..... outside of the onmessage handler.

更新:我应该仔细观察,但要监视的事件是 event1,因此我们需要为该事件设置一个事件侦听器.

UPDATE: I should have looked closer but the event to monitor is event1 so we need to set an event listener for that event.

<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>

对于 SSE 服务器脚本,我倾向于采用这样的方法

As for the SSE server script I tend to employ a method like this

<?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();
    }
?>

这篇关于使用while循环时服务器端PHP事件页面未加载的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆