【问题标题】:Retrieving chat messages with AJAX script based on time they were sent根据发送时间使用 AJAX 脚本检索聊天消息
【发布时间】:2012-02-06 14:51:39
【问题描述】:

我正在为我的任务构建一个带有房间的实时聊天应用程序。到目前为止一切都很好,但我无法从数据库中正确检索最新的聊天消息。消息表具有以下字段:

| m_id | u_id | r_id | message | sent |

m_id 是主键。 u_idr_id 是其他表的外键,用于引用发送消息的用户和他们发送消息的房间。 sent 字段包含 PHP 的 microtime(true) 格式的数据:

1326174129.977

我已经构建了我的 AJAX 脚本来从数据库中检索消息,它看起来像这样:

function getMessages() {
    var d = new Date();
    $.post("/ajax/getmessages.php", {roomID: roomID, timestamp: timestamp}, function(resp) {
        resp = $.parseJSON(resp);

        for(x in resp) {
            $('#chat-holder ul').append('<li>[' + d.getHours() + ':' + d.getMinutes() + ':' + d.getSeconds() + '] <strong>' + resp[x].u_id + '</strong>: ' + resp[x].msg + '</li>');
            $("#chat-holder").scrollTop($("#chat-holder")[0].scrollHeight);
        }
    });
}

getMessages 函数每秒运行一次,然后当它从getmessages.php 脚本检索数据时,它会循环遍历 JSON 编码的响应和广告列表项到聊天框架。很简单。

问题在于,它会检索发送到房间的所有消息,而不仅仅是自用户上次轮询最新消息以来已发送的消息。因此,我最终将聊天中发送的每条消息每秒都添加到聊天框架中。

我想出的唯一方法是存储用户最后一次请求消息的时间戳,然后以某种方式在我的后端 PHP 脚本中使用它。不幸的是,我不太清楚如何实现它。

非常感谢任何帮助,谢谢。

【问题讨论】:

    标签: php javascript mysql ajax


    【解决方案1】:

    鉴于这个想法与其说是在给定时间后获取所有消息,不如说是获取自上一批消息以来的所有消息,我认为根据您的消息表的主要内容来执行此操作会更容易键而不是时间戳字段。创建一个客户端变量来记录迄今为止最高(已知)的 id:

    var highestMessageId = 0;
    

    然后,当您发出 ajax 请求时,将该 id 传递给 PHP:

    $.post("/ajax/getmessages.php", {roomID: roomID, fromMessageId : highestMessageId},
    

    然后在你的 PHP 中:

    SELECT * FROM messages
    WHERE r_id = $r_id
    AND   m_id > $m_id
    

    然后,在 ajax 成功处理程序中,您使用新批次中最后一条记录的 id 更新 highestMessageId

    当然,这假设您的表使用标准数字键,其中稍后添加的记录具有比之前添加的记录更高的键...

    编辑:现在我想一想,完全相同的过程也适用于时间戳字段。当我开始写上面的内容时,我认为时间戳不起作用是有原因的,但我认为我只是在担心一个非问题(我在考虑 ajax 请求的时间而不是时间戳上的时间戳)记录)。

    【讨论】:

      【解决方案2】:

      是的,你的想法是正确的。

      $.post("/ajax/getmessages.php", {roomID: roomID, timestamp: timestamp},
      

      那个时间戳是从哪里来的?

      无论如何,在服务器上你应该这样做(伪代码):

      SELECT * 
      FROM messages
      WHERE r_id = $roomID AND sent > $timestamp
      ORDER BY sent;
      

      然后您将该数据连同最新的时间戳(sent 最后一行的值)发送到客户端。

      {timestamp: $last_sent,
       messages: [...]
      }
      

      然后,在您的 AJAX 回调中执行以下操作:

      resp = $.parseJSON(resp);
      
      last_timestamp = resp['timestamp'];
      
      for(x in resp['messages']) {
        // ...
      }
      

      然后你在下一个请求中使用last_timestamp

          $.post("/ajax/getmessages.php", {roomID: roomID, timestamp: last_timestamp}, ...
      

      转到第 1 步 :-)

      【讨论】:

        【解决方案3】:

        例如,将WHERE created &gt; DATE_SUB(date(NOW()), INTERVAL 1 hour) ORDER BY created 子句添加到您的 SQL 中。

        【讨论】:

          【解决方案4】:

          我建议您不要使用时间戳,而是使用 id 来下载最新消息。当您的数据库中有数千/数百万条消息时,这将带来更好的性能。

          另外,我不会每秒下载消息,而是在服务器上延迟它,这意味着服务器在至少有一条新消息到达之前不会给出响应。像这样:

          $start = time();
          $query = mysql_query(...);
          while(mysql_num_rows($query)==0 && time()-$start < 25) {
             usleep(200000); // we wait for 200 ms so the server won't be overloaded
             $query = mysql_query(...);
          }
          //print out the results
          

          在客户端得到结果后,不要拖延,立即发出下一个请求。

          【讨论】:

            【解决方案5】:

            将上次检索到的时间戳保存在localstorage

            <script>
            var last_timestamp=localStorage.getItem('last_timestamp')||1;
            $.post("/ajax/getmessages.php", {roomID: roomID, timestamp: last_timestamp}, function(resp) {
                    resp = $.parseJSON(resp);
               //save last retrieved id 
            localStorage.setItem('last_timestamp', resp.new_timestamp);
            .....
            </script>
            

            当然,浏览器必须支持 localStorage 才能工作。

            【讨论】:

              猜你喜欢
              • 1970-01-01
              • 2023-01-27
              • 1970-01-01
              • 1970-01-01
              • 2016-04-29
              • 1970-01-01
              • 2017-09-27
              • 2020-12-30
              • 1970-01-01
              相关资源
              最近更新 更多