Ajax 和 XML: 将 Ajax 用于聊天

  了解如何使用 Asynchronous JavaScript™ + XML (Ajax) PHP Web 用程序中建立聊天系。您的客不需要下或安装任何专门的即消息通讯软件,就能和您及其他客户讨论网站的内容。

Web 2.0 以来, 开发 都在 社区。不 您是否 认为这 有点夸大其辞,但 者能 方便地 实时讨论页 面主 或者 售的 品, 一想法 是很吸引人的。但是怎 么办 呢?能否在推 销产 品的 面中加入聊天,而不必 安装任何特殊的 件包括 Adobe Flash Player 呢?当然! 明,用免 成工具如 PHP MySQL 动态 HTML (DHTML) Ajax Prototype.js 就能完全做到。
不再 罗嗦 了, 立即 始吧。
聊天首先要有一个身份 标识 就需要一个 简单 的登 录页 ,如 清单 1 所示。

单 1. index.html

               
<html>
<head><title>Chat Login</title></head>
<body>
<form action="chat.php" method="post">
Username: <input type="text" name="username">
<input type="submit" value="Login">
</form>
</body>
</html>

 
该页 果如 图 1 所示。
1. 聊天登录窗口
Ajax 和 XML: 将 Ajax 用于聊天_第1张图片
 
注意:该 例中需要登 窗口是因 我希望知道 说话 于您的 用程序,可能已 在一个登 录页 面,使用自己已有的用 名即可。
 
 
基本的聊天系
聊天系 统实质 上就是一个字符串表格, 个字符串属于一个 言者。最 简单 的模式如 清单 2 所示。

单 2. chat.sql
               
DROP TABLE IF EXISTS messages;
 
CREATE TABLE messages (
 message_id INTEGER NOT NULL AUTO_INCREMENT,
 username VARCHAR(255) NOT NULL,
 message TEXT,
 PRIMARY KEY ( message_id )
);
 
脚本中包含自 增加的消息 ID 、用 名和消息本身。如果需要, 可以向 条消息增加 时间 戳以 记录发 送的 时间
如果需要管理不同 话题 的多个会 需要建立一个表 记录 不同的 话题 ,并在消息表中增加相 topic_id 了尽量 化例子,我采用了最 简单 的模式。
建立数据 和加 模式使用了下列命令:
% mysqladmin create chat
% mysql chat < chat.sql
 
根据 MySQL 器的 置及其安全 定和口令,命令可能略有不同。
最基本的聊天用 界面( UI )如 清单 3 所示。

单 3. chat.php
               
<?php
if ( array_key_exists( 'username', $_POST ) ) {
 $_SESSION['user'] = $_POST['username'];
}
$user = $_SESSION['user'];
?>
<html>
<head><title><?php echo( $user ) ?> - Chatting</title>
<script src="prototype.js"></script>
</head>
<body>
 
<div id="chat" style="height:400px;overflow:auto;">
</div>
 
<script>
function addmessage()
{
 new Ajax.Updater( 'chat', 'add.php',
 {
 method: 'post',
 parameters: $('chatmessage').serialize(),
 onSuccess: function() {
 $('messagetext').value = '';
 }
 } );
}
</script>
 
<form id="chatmessage">
<textarea name="message" id="messagetext">
</textarea>
</form>
 
<button onclick="addmessage()">Add</button>
 
<script>
function getMessages()
{
 new Ajax.Updater( 'chat', 'messages.php', {
 onSuccess: function() { window.setTimeout( getMessages, 1000 ); }
 } );
}
getMessages();
</script>
 
</body>
</html>
 
在脚本的 始部分中,您可从登 录页 面提交的参数中 取用 名并存 在会 中。然后加 Prototype.js JavaScript ,它可以完成所有 Ajax 理。
然后 面提供了存放消息的位置。 区域由文件后面的 getMessages() JavaScript 函数填写。
消息区域的下面是一个表 和用 户输 入消息文本的 textarea 有一个按 钮Add 添加聊天消息。
面如 图 2 所示。

2. 简单的聊天窗口
Ajax 和 XML: 将 Ajax 用于聊天_第2张图片
注意 getMessages() 函数, 实际 1000 毫秒( 1 秒) 轮询 一次服 器, 检查 是否有新消息,并把 出到 面上方的消息区域。本文 后面 详细 绍轮询 ,我想首先完成基本的 实现 messages.php 面返回当前的消息列表。 该页 4 所示。

单 4. messages.php
               
<table>
<?php
require_once("DB.php");
 
$db =& DB::Connect( 'mysql://root@localhost/chat', array() );
if (PEAR::isError($db)) { die($db->getMessage()); }
 
$res = $db->query('SELECT * FROM messages' );
while( $res->fetchInto( $row ) )
{
?>
<tr><td><?php echo($row[1]) ?></td>
<td><?php echo($row[2]) ?></td></tr>
<?php
}
?>
</table>
 
脚本的一 始用 DB 库连 接到数据 可从 PEAR 参考资料 )。如果 没有安装 ,可通 下面的命令完成:
% pear install DB
 
PEAR 安装后,脚本可以 查询 当前的消息, 一行, 出用 名和消息文本。
最后 add.php 脚本,从 面上 addmessage() 函数的 Prototype.js Ajax 用。 脚本从会 中取得消息文本和用 名,然后在消息表中插入新的一行。代 5 所示。

单 5. add.php
               
<?php
require_once("DB.php");
 
$db =& DB::Connect( 'mysql://root@localhost/chat', array() );
if (PEAR::isError($db)) { die($db->getMessage()); }
 
$sth = $db->prepare( 'INSERT INTO messages VALUES ( null, ?, ? )' );
$db->execute( $sth, array( $_SESSION['user'], $_POST['message'] ) );
?>
<table>
<?php
$res = $db->query('SELECT * FROM messages' );
while( $res->fetchInto( $row ) )
{
?>
<tr><td><?php echo($row[1]) ?></td>
<td><?php echo($row[2]) ?></td></tr>
<?php
}
?>
</table>
 
add.php 脚本 返回当前的消息列表,因 面中的 Ajax 要从返回的 HTML 更新聊天 记录 这样 就能 上看到添加到会 中的文本。
聊天系 的基本 构就是 些。下一 节说 明如何改 进轮询 的效率。
一点改
个原始的聊天系 中, 求一次 对话 的所有聊天 记录 短的 对话 影响不大,但是如果 对话 ,性能 问题 显现 出来了。所幸的是解决起来很 简单 条消息都有 message_id 个数字自 动递 增。因此,如果知道已 有了属于某个 ID 的消息,只需要 求出 在此 ID 之后的消息就可以。 这样 可以大大降低消息 传递 的数量。多数 求很可能没有新的消息, 传递 的包就会 小。
采用效率更高的 设计 需要稍微修改 chat.php 面,如 清单 6 所示。

单 6. chat.php(修改)
               
<?php
if ( array_key_exists( 'username', $_POST ) ) {
 $_SESSION['user'] = $_POST['username'];
}
$user = $_SESSION['user'];
?>
<html>
<head><title><?php echo( $user ) ?> - Chatting</title>
<script src="prototype.js"></script>
</head>
<body>
 
<div style="height:400px;overflow:auto;">
<table id="chat">
</table>
</div>
 
<script>
function addmessage()
{
 new Ajax.Request( 'add.php', {
 method: 'post',
 parameters: $('chatmessage').serialize(),
 onSuccess: function( transport ) {
 $('messagetext').value = '';
 }
 } );
}
</script>
 
<form id="chatmessage">
<textarea name="message" id="messagetext">
</textarea>
</form>
 
<button onclick="addmessage()">Add</button>
 
<script>
var lastid = 0;
function getMessages()
{
 new Ajax.Request( 'messages.php?id='+lastid, {
 onSuccess: function( transport ) {
 var messages = transport.responseXML.getElementsByTagName( 'message' );
 for( var i = 0; i < messages.length; i++ )
 {
 var message = messages[i].firstChild.nodeValue;
 var user = messages[i].getAttribute('user');
 var id = parseInt( messages[i].getAttribute('id') );
 
 if ( id > lastid )
 {
 var elTR = $('chat').insertRow( -1 );
 var elTD1 = elTR.insertCell( -1 );
 elTD1.appendChild( document.createTextNode( user ) );
 var elTD2 = elTR.insertCell( -1 );
 elTD2.appendChild( document.createTextNode( message ) );
 
 lastid = id;
 }
 }
 window.setTimeout( getMessages, 1000 );
 }
 } );
}
getMessages();
</script>
 
</body>
</html>
 
不再用 “chat” <div> 标记 包含所有的消息, 在改 <table> 标记 ,收到新消息的 动态 地追加一行。可以看到 getMessages() 函数中的相 应变 化,和第一个版本相比 了一些。
新版本的 getMessages() messages.php 面的 果是包含新消息的 XML messages.php 增加了一个参数 id ,即 示的最后一条消息的 message_id 。一 ID 0 ,因而 messages.php 面返回所有的消息。此后 则发 送到目前 的最后一条消息的 ID
XML onSuccess 理程序分解成元素, 个元素使用 DHTML 文档 象模型( DOM )函数添加到表格中,如 insertRow() insertCell() appendChild()
修改后的 messages.php 文件返回 XML 而不是 HTML ,如 7 所示。
 
7. messages.php
               
<?php
require_once("DB.php");
 
header( 'Content-type: text/xml' );
 
$id = 0;
if ( array_key_exists( 'id', $_GET ) ) { $id = $_GET['id']; }
 
$db =& DB::Connect( 'mysql://root@localhost/chat', array() );
if (PEAR::isError($db)) { die($db->getMessage()); }
?>
<messages>
<?php
$res = $db->query( 'SELECT * FROM messages WHERE message_id > ?', $id );
while( $res->fetchInto( $row ) )
{
?>
<message id="<?php echo($row[0]) ?>" user="<?php echo($row[1]) ?>">
<?php echo($row[2]) ?>
</message>
<?php
}
?>
</messages>
 
图 3 示了新的改 后的版本。

3. 经过优化的聊天窗口
Ajax 和 XML: 将 Ajax 用于聊天_第3张图片
从外 上来 没有什 。但是和原来的相比效率要高得多。
 
实时 的秘密
如果 接触 Ajax 或者 仅对该领 域有所了解, 轮询 的概念可能 您感到害怕。不幸的是, 轮询 是惟一的 法。要在客 机和服 器之 建立 连续 管道,同 又不需要在两端安装特定 件,尚不存在可 实现 此目的的跨平台、跨 浏览 器方法。即便 这样 ,可能 需要 防火 墙进 专门 配置才行得通。因此,如果需要人人能用的一 种简 便 法, Ajax 轮询 是惟一的可能。
但是不断宣 和鼓吹的 实时 在哪儿呢? 轮询 不可能是 实时 的。真的如此 ?我 认为这 取决于您 实时 的定 。我 生理学数据 索代 码时 实时 意味着毫秒。我相信地 学家在某些情况下把分、日甚至年看作是 实时
如果 查阅 Wikipedia ,即会 发现 的平均反 应时间 200 270 毫秒之 。也就是 一次球的 时间 阅读 一条消息并形成答 时间 得多,即使您非常投入。因此,等待聊天消息 200 毫秒左右(可能再 一点)的 时间应该 了。我 1 秒,而且没有感 到不舒服。
developerWorks Ajax 论坛 参考资料 )的主持人, 轮询 实时 问题每 月至少遇到一次。我希望 Ajax 经揭 穿了 轮询 和所 实时 的面具。建 在考 极其 复杂 实时 解决方案之前 尝试 一下 轮询 这样 至少可以知道 尝试 自定 的解决方案之前使用 成的工具能 做什
 
此后的工作
希望本文 您提供了一个不 的起点,以此 在您的 用程序中 实现 自己的聊天系 下面是一些建
  • 记录在聊天窗口的旁列出目前参加会的人这样可以告们谁参加了谈话,什么时候来的,什么时候退出的。
  • 多个会多个于不同话题谈话时进行。
  • 支持表情字符::-)这样的字符合翻成适当的笑脸图像。
  • 使用 URL 解析:在客 JavaScript 中使用正表达式发现 URL 化成超接。
  • Enter 取消 Add ,通过检查textareaonkeydown事件看看用是否按下了 Enter Return
  • 示用户输时间户开入的候通知服器,会的其他人可以看到有人在回这样如果有人打字慢可以将谈话结束的感减到最低。
  • 限制消息的大小:保持谈话顺畅的另一个法是避免消息过长限制textarea中的最大字符数onkeydown有助于提高交的速度。
这仅仅 是修改上述代 码进 行改 的部分想法。如果您 这样 做了并且希望在社区中分享您的成果, 我,我可以将其放到 下载 的源代 中。
 
我承 我不大喜 聊天。我从未打 我的聊天客 机。很 长时间 使用 一次文本消息。我的聊天 标识 符是 idratheryouemail 够严肃 的。不 发现结 合当前 境的聊天,比如本文所述的 这种 情况很吸引人。 ?因 它主要集中在网站有 的主 上,可以最大限度的避免 于最近 “TomKat” 闻这类 拉西扯。
在您的 Web 用程序中 尝试这 段代 看看能否 您的 者和客 户进 实时 ,并通 developerWorks Ajax 论坛 我效果如何。希望能 您以惊喜。

 

参考
  • 您可以参本文在 developerWorks 全球网站上的 英文原文
  • 订阅 Ajax XML 系列 RSS 提要
  • Ajax 术资源中心developerWorks 上所有有 Ajax 问题都可以在里找到解答。
  • 订阅 Ajax 文章和教程 RSS 提要得即将表的 Ajax 文章和教程的通知( developerWorks 内容 RSS 提要 了解更多的信息)。
  • PHP 主页 PHP 程序提供了大量参考料。
  • Prototype JavaScript Framework 可以动态 Web 用程序的开发
  • Scriptaculous JavaScript 个基于 Prototype 的框架提供的示帮助器和特效可以改善您的网站。
  • Prototype.js 文档 Prototype JavaScript 的其他信息,包括到官方 Prototype blog 和很多其他源的接。
  • jQuery:提供了和 Prototype.js 功能似的另一个 JavaScript
  • Yahoo! User Interface Library:看看 Yahoo! Ajax 工具箱。
  • developerWorks XML :通 developerWorks XML 区了解 XML 的方方面面。
  • IBM XML 认证:了解如何才能成一名 IBM 认证 XML 及相开发
  • XML 文档developerWorks XML 区提供了大量技文章和技巧、教程、准以及 IBM
  • developerWorks 事件和网广播:随时关注技的最新

你可能感兴趣的:(Ajax 和 XML: 将 Ajax 用于聊天)