使用PHP的服务器发送事件无法正确显示数据

时间:2014-12-24 22:14:06

标签: javascript php html5 apache server-sent-events

我正在尝试使用ajax发布创建最简单的聊天应用,并尝试使用SSE推送数据。我刚刚遇到SSE并尝试了它。现在的问题是

  1. 如何控制服务器何时推送数据,因为它每3秒推送一次数据。

  2. 为什么当我选择整个MySQL行只显示浏览器中的最后一行但推送所有内容时(在网络选项卡中选中)

  3. 这是我的代码:

    的index.html

    <script>
    
    var source = new EventSource("server.php");
    
    source.addEventListener("message", function(event){
    
    $("#box").html(event.data);
    
    });
    
    </script>
    
    <script type="text/javascript">
    
    function chat_pressed(){
    
        var chat = $('#chat_text').val();
    
        var data = {action : "send_chat", chat : chat};
    
        $.ajax({
            type : "POST",
            url : "chat.php",
            data : data,
            success : function(r){
                $('#chat_text').val("");
            }
    
        })
    
    
    }
    
    </script>
    
    <input type="text" id="chat_text" />
    <input type="button" onClick="chat_pressed();"  value="POST"/>
    <br /><hr />
    <div id="box"></div>
    

    server.php

    header('Content-Type: text/event-stream');
    header('Cache-Control: no-cache');
    
    include("connect.php");
    
    
    $sql = $db->prepare("SELECT * FROM chat");
    $sql->execute();
    
    while($row = $sql->fetch(PDO::FETCH_ASSOC)){
        $chat = $row['chat'];
    echo "data: $chat \n\n";
    }
    
    ob_flush();
    flush();
    
    //sleep(2);
    
    1. 当我将index.html更改为$("#box").html(event.data);时{} $("#box").append(event.data);,它会一遍又一遍地显示所有行。基本上附加。
    2. 这里发生的事情是,当我保留$("#box").html(event.data);

      时,它只显示最后一行
      1. 当我在server.php上写echo "data:".$chat."<br />"时,它就没有推动任何东西。

        我想要的是控制服务器推送事物,并在表更新时仅将最后一行数据附加到当前数据。而且我想知道echoing数据的正确方法,因为当divs等复杂的事情发生时,正如我所理解的那样,所有这些都会变得困难。这里的任何帮助将不胜感激..

1 个答案:

答案 0 :(得分:0)

您的server.php进程在发送一位数据后结束。这意味着插座关闭。浏览器看到套接字已经死亡并在3秒后重新连接。这就是为什么看起来它每3秒推送一次数据。相反,你需要更改你的server.php以拥有一个无限循环,其中有一个睡眠,并轮询mysql:

header('Content-Type: text/event-stream');
header('Cache-Control: no-cache');

include("connect.php");

$previousID = 0;

while(true){
    $sql = $db->prepare("SELECT * FROM chat WHERE id > ?");
    $sql->execute( array($previousId) );
    while($row = $sql->fetch(PDO::FETCH_ASSOC)){
        $chat = $row['chat'];
        echo "data: $chat \n\n";
        //TODO: update $previousID here
    }

    ob_flush();
    flush();

    sleep(10);  //Poll every 10 seconds
}

此(未经测试的)代码还显示了每次只发送新数据的方法。你需要让它更健壮 - 如果收到0行,你可能想发送心跳来告诉客户端最后的轮询时间,例如。

对于第二个问题,您为每个发送的数据调用了消息处理程序,然后执行:

$("#box").html(event.data);

这意味着每个新数据都会覆盖前一个数据;因为所有数据行都在同一时间到达,所以你在屏幕上看到的只是最后到达的数据行。

如果您希望所有行都在屏幕上,请考虑使用<li>标记和jQuery的append()。在我的书(PLUG:带有HTML5 SSE的数据推送应用程序 - O'Reilly)中,我经常附加到<pre>标签,作为查看到达所有数据的快捷方式。