使用AJAX脚本根据发送时间检索聊天消息

时间:2012-01-10 05:52:48

标签: php javascript mysql ajax

我正在为我的作业构建一个实时聊天应用程序。到目前为止,一切都很顺利,但我无法从数据库中正确检索最新的聊天消息。消息表包含以下字段:

| 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脚本中使用它。不幸的是,我无法理解如何实现它。

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

4 个答案:

答案 0 :(得分:1)

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

$.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步: - )

答案 1 :(得分:1)

鉴于这个想法不是在给定时间之后获取所有消息以至于获取自上一批消息以来的所有消息,我认为根据您的消息表的主要消息更容易做到这一点键而不是时间戳字段。创建一个客户端变量来记录到目前为止最高(已知)的id:

var highestMessageId = 0;

然后,当你将ajax请求传递给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 :(得分:0)

例如,

WHERE created > DATE_SUB(date(NOW()), INTERVAL 1 hour) ORDER BY created子句添加到SQL中。

答案 3 :(得分:0)

我建议您不要使用时间戳,而是使用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

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