问题是如何以自然的方式不断更新界面,以及如何在私人聊天中显示“X正在输入..”消息。
显而易见的方式似乎是每X秒/毫秒javascript ping服务器,并获取一个新的邮件列表之间的最后一个ping和现在。然而,这可以使接口看起来有点不自然,如果突然聊天室充斥着5条消息。我宁愿每个消息显示,因为它是键入。
有没有办法让javascript来维护与服务器的连续连接,服务器将任何新消息推送到此连接,并且javascript将它们添加到接口,以便它们同时显示,几乎只要服务器收到它们?
我知道有一些轮询选项,需要你安装一些apache模块等,但我很糟糕的sysadmin,因此我更喜欢如果有一个很容易安装解决方案在共享的主机帐户,或者PHP / MysqL only解决方案。
解决方法
我使用这本书/教程来编写我的聊天应用程序:
AJAX and PHP: Building Responsive Web Applications: Chapter 5: AJAX chat and JSON。
它显示如何从头写一个完整的chatscript。
基于彗星的聊天
发件人:zeitoun:
Comet使Web服务器可以向客户端发送数据,而不需要客户端请求它。因此,这种技术将产生比传统的AJAX更响应的应用程序。在经典的AJAX应用程序中,无法实时通知Web浏览器(客户端)服务器数据模型已更改。用户必须创建一个请求(例如通过点击一个链接)或者定期发送AJAX请求,以便从服务器获取新数据。
>基于隐藏的< iframe>使用服务器时间戳
>基于经典的AJAX非返回请求
方法1:iframe服务器时间戳
你需要:
>后端PHP脚本来处理持久的http请求backend.PHP
>一个frondend HTML脚本加载Javascript代码index.html
> prototype JS library,但你也可以使用jQuery
后端脚本(backend.PHP)将执行无限循环,并且只要客户端连接,就会返回服务器时间。
<?PHP header("Cache-Control: no-cache,must-revalidate"); header("Expires: Sun,5 Mar 2012 05:00:00 GMT"); flush(); ?> <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd"> <html xmlns="http://www.w3.org/1999/xhtml"> <head> <title>Comet PHP backend</title> <Meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> </head> <body> <script type="text/javascript"> // KHTML browser don't share javascripts between iframes var is_khtml = navigator.appName.match("Konqueror") || navigator.appVersion.match("KHTML"); if (is_khtml) { var prototypejs = document.createElement('script'); prototypejs.setAttribute('type','text/javascript'); prototypejs.setAttribute('src','prototype.js'); var head = document.getElementsByTagName('head'); head[0].appendChild(prototypejs); } // load the comet object var comet = window.parent.comet; </script> <?PHP while(1) { echo '<script type="text/javascript">'; echo 'comet.printServerTime('.time().');'; echo '</script>'; flush(); // used to send the echoed data to the client sleep(1); // a little break to unload the server cpu } ?> </body> </html>
前端脚本(index.html)创建一个“彗星”javascript对象,将后端脚本连接到时间容器标记。
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd"> <html xmlns="http://www.w3.org/1999/xhtml"> <head> <title>Comet demo</title> <Meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> <script type="text/javascript" src="prototype.js"></script> </head> <body> <div id="content">The server time will be shown here</div> <script type="text/javascript"> var comet = { connection : false,iframediv : false,initialize: function() { if (navigator.appVersion.indexOf("MSIE") != -1) { // For IE browsers comet.connection = new ActiveXObject("htmlfile"); comet.connection.open(); comet.connection.write("<html>"); comet.connection.write("<script>document.domain = '"+document.domain+"'"); comet.connection.write("</html>"); comet.connection.close(); comet.iframediv = comet.connection.createElement("div"); comet.connection.appendChild(comet.iframediv); comet.connection.parentWindow.comet = comet; comet.iframediv.innerHTML = "<iframe id='comet_iframe' src='./backend.PHP'></iframe>"; } else if (navigator.appVersion.indexOf("KHTML") != -1) { // for KHTML browsers comet.connection = document.createElement('iframe'); comet.connection.setAttribute('id','comet_iframe'); comet.connection.setAttribute('src','./backend.PHP'); with (comet.connection.style) { position = "absolute"; left = top = "-100px"; height = width = "1px"; visibility = "hidden"; } document.body.appendChild(comet.connection); } else { // For other browser (Firefox...) comet.connection = document.createElement('iframe'); comet.connection.setAttribute('id','comet_iframe'); with (comet.connection.style) { left = top = "-100px"; height = width = "1px"; visibility = "hidden"; display = 'none'; } comet.iframediv = document.createElement('iframe'); comet.iframediv.setAttribute('src','./backend.PHP'); comet.connection.appendChild(comet.iframediv); document.body.appendChild(comet.connection); } },// this function will be called from backend.PHP printServerTime: function (time) { $('content').innerHTML = time; },onUnload: function() { if (comet.connection) { comet.connection = false; // release the iframe to prevent problems with IE when reloading the page } } } Event.observe(window,"load",comet.initialize); Event.observe(window,"unload",comet.onUnload); </script> </body> </html>
方法2:AJAX非返回请求
您需要与方法1中相同的dataexchange(data.txt)文件,
现在,backend.PHP将做2件事:
>发送新消息时写入“data.txt”
>做一个无限循环,只要“data.txt”文件不变
06002
$_GET[‘timestamp’] : 0;
$currentmodif = filemtime($filename);
while ($currentmodif <= $lastmodif) // check if the data file
has been modified
{
usleep(10000); // sleep 10ms to unload the cpu
clearstatcache();
$currentmodif = filemtime($filename);
}06003
前端脚本(index.html)创建< div id =“content”>< / div>标签帽子将包含来自“data.txt”文件的聊天消息,最后它创建一个“彗星”javascript对象,它将调用后端脚本以便观看新的聊天消息。
彗星对象将在每次接收到新消息时和每次发布新消息时发送AJAX请求。持久连接仅用于观看新消息。时间戳url参数用于标识最后请求的消息,以便服务器只有在“data.txt”时间戳比客户端时间戳更新时才会返回。
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd"> <html xmlns="http://www.w3.org/1999/xhtml"> <head> <title>Comet demo</title> <Meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> <script type="text/javascript" src="prototype.js"></script> </head> <body> <div id="content"> </div> <p> <form action="" method="get" onsubmit="comet.doRequest($('word').value);$('word').value='';return false;"> <input type="text" name="word" id="word" value="" /> <input type="submit" name="submit" value="Send" /> </form> </p> <script type="text/javascript"> var Comet = Class.create(); Comet.prototype = { timestamp: 0,url: './backend.PHP',noerror: true,initialize: function() { },connect: function() { this.ajax = new Ajax.Request(this.url,{ method: 'get',parameters: { 'timestamp' : this.timestamp },onSuccess: function(transport) { // handle the server response var response = transport.responseText.evalJSON(); this.comet.timestamp = response['timestamp']; this.comet.handleResponse(response); this.comet.noerror = true; },onComplete: function(transport) { // send a new ajax request when this request is finished if (!this.comet.noerror) // if a connection problem occurs,try to reconnect each 5 seconds setTimeout(function(){ comet.connect() },5000); else this.comet.connect(); this.comet.noerror = false; } }); this.ajax.comet = this; },disconnect: function() { },handleResponse: function(response) { $('content').innerHTML += '<div>' + response['msg'] + '</div>'; },doRequest: function(request) { new Ajax.Request(this.url,parameters: { 'msg' : request }); } } var comet = new Comet(); comet.connect(); </script> </body> </html>
或者
你也可以看看其他聊天应用程序,看看他们是如何做到的:
> http://hot-things.net/?q=blite – BlaB! Lite是一个基于AJAX的,最好的浏览器支持任何浏览器聊天系统,sqlite& Postgresql数据库。
> Gmail/Facebook Style jQuery Chat – 此jQuery聊天模块使您能够将Gmail / Facebook风格聊天无缝集成到您的现有网站。
> Writing a JavaScript/PHP Chat Server – 教程
> CometChat – CometChat在标准共享服务器上运行。只有PHP MysqL需要。