一个iframe实现长轮询,通过PHP查询数据库并用JS更新页面内容的程序,问题是并不是每一条MYSQL的INSERT消息都能显示到页面,求帮忙分析下哪里有问题
首先,这是一个仿客服咨询的实时通讯系统,主要目的是将模拟前台用户发送的消息(通过手动INSERT进MYSQL数据库实现)由服务器实时推送到前台客服页面上,大致结构如下:
1、在前台kefu.html页面上有一个iframe,这个iframe请求后台query.php查询程序(iframe在页面上隐藏了)
2、query.php通过一个while(true)死循环并设置set_time_limit(0),然后,在循环中不断的进行SQL查询,将用户发送的未读的消息查询出来,并通过输出<script></script>JS代码,操作父页面的区,将查询出来的消息结果输出到页面上
3、我通过手动INSERT一些数据,来模拟用户的消息提交, 默认消息是未读状态,当query.php读取后,会改变其为已读状态
现在的问题是:当我打开页面后(或者关闭页面再重新打开程序),一般最开始插入的数据都不能被显示到页面上,但是这些消息的状态却已经被query.php改为已读(也就是query.php已经查询到这条记录并发送JS代码到前端了),而当我继续插入很多条之后,前端才开始显示记录,并且之前INSERT的记录都是被标记为已读状态了,但是却没有显示到前台kefu.html页面上,要插入很多条之后,或者等一段时间后才能恢复正常
整个程序并没有问题,因为之后的程序就是正常的可以一条一条显示了,插入一条前台就显示一条(但是偶尔中途也会丢失一条)
我猜测问题的根源可能有两点:
1、PHP的脚本并没有被结束
2、JS可能有缓存导致虽然接收到了数据,但没有更新
不过以上两点我都不确定,我觉得可能问题没这么简单,应该是违反或者没有注意某个机理而造成的。
具体代码如下,还请各位帮忙看看问题出在了什么地方,也可以本地测试下,谢谢了。
测试方法:
手动在数据库中INSERT数据,然后观察前台kefu.html页面是否能及时收到并更新消息
数据库建表:
CREATE TABLE msg(
id int(11) NOT NULL auto_increment,
pos varchar(20) NOT NULL default '',
rec varchar(20) NOT NULL default '',
content varchar(200) NOT NULL default '',
isread` int(1) NOT NULL default '0',
PRIMARY KEY(id)
);
插入数据示例:
insert into msg(rec,pos,content,isread) values('admin','zhangsan','hello',0);
回复讨论(解决方案)
前台kefu.html代码:
<?php setcookie('username','admin');?><!doctype html><html> <head> <title>在线客服系统</title> <meta charset="utf-8" /> <script> //测试浏览器是Chrome 27.0.1453.93 var xhr = new XMLHttpRequest(); //由query.php程序调用的JS函数,用来输出内容到前台页面 function comet(msg,rand){ var content = ''; //获取用户发送给前台的消息,并拼接好 content = '<span onclick="reply(this);" style="cursor:pointer;">' + msg.pos + ' </span>' + '对你说:<br/> ' + msg.content + '<br/>'; var msgzone = document.getElementById('msgzone'); //把拼接的消息赋值给消息显示区域 msgzone.innerHTML += content; } //点击某个用户名,然后回复的span会显示该用户名 function reply(reobj){ document.getElementById('rec').innerHTML = reobj.innerHTML } //前台客服回复时,调用的函数 function huifu(){ var rep = ''; //接收前台发送的用户名字 var rec = document.getElementById('rec').innerHTML; //前台发送的消息内容 var content = document.getElementsByTagName('textarea')[0].value; if(rec == '' || content == ''){ alert('请选择回复人并填写回复内容');//简单判断回复对象和内容不能为空 return; } //sendmsg.php是专门配套前台发送消息用的,就是把消息INSERT进数据库 xhr.open('POST','sendmsg.php',true); xhr.setRequestHeader('Content-Type','application/x-www-form-urlencoded'); xhr.onreadystatechange = function(){ if(this.readyState == 4 && this.status == 200){ if(this.responseText == 'ok'){ //当确定前台发送的消息INSERT进数据库后,把这条消息显示到消息区域内 rep += '你对 ' + rec + '说:<br/> ' + content + '<br/>'; var msgzone = document.getElementById('msgzone'); msgzone.innerHTML += rep; document.getElementsByTagName('textarea')[0].value = ''; } } } xhr.send('rec='+rec+'&content='+content); } </script> <style> #msgzone{ border:1px solid #ececec; width:500px; height:500px; overflow:scroll; } </style> </head> <body> <h1 id="在线客服系统-客服端">在线客服系统--客服端</h1> <!-- 消息显示区域 --> <div id="msgzone"></div> <!-- 用户名区域 --> 回复:<span id="rec"></span><br/> <!-- 回复内容区域 --> <textarea> </textarea><input type="button" value="回复" onclick="huifu();" /> <!-- 隐藏的iframe,其中加载了query.php来不断查询数据库是否有要推送的消息 --> <iframe src="query.php" width="0" height="0" iframeBorder="0"></iframe> </body></html>
后端查询query.php代码:
<?phpset_time_limit(0);ob_start();echo str_repeat(' ',4000),'<br/>';ob_flush();flush();$i = 0;require 'conn.php';//连接数据库文件//不断循环查询消息while(true){ //查询接收者为admin,并且是未读的消息 $sql = 'select * from msg where rec = "admin" and isread = 0 limit 1'; $result = $conn -> query($sql); //提取查询结果 $rs = $result -> fetch_assoc(); if(!empty($rs)){ //将这条消息更新为已读状态 $sql = 'update msg set isread = 1 where id = "'.$rs['id'].'" limit 1'; $conn -> query($sql); //转换为JSON格式准备发送给JS $rs = json_encode($rs); //通过paren调用父窗体的comet()函数,并将转换的JSON数据传送过去,comet()函数可以在kefu.html代码中找到 echo '<script>'; echo 'parent.window.comet(',$rs,',',mt_rand(1,1000000),')'; echo '</script>'; } ob_flush(); flush(); //防止查询次数过多,设置的每1秒查询一次 sleep(1);}
数据库连接conn.php代码:
<?php $conn = new mysqli('localhost','root','jackson613','test'); $conn -> query('set names utf8');
建议还是采用AJAX的轮询方式,这种的后台查询脚本里没有主动结束脚本执行,可能存在一定问题。
我测试的是只能显示一个 后面的都显示不出来

负载均衡会影响会话管理,但可以通过会话复制、会话粘性和集中式会话存储解决。1.会话复制在服务器间复制会话数据。2.会话粘性将用户请求定向到同一服务器。3.集中式会话存储使用独立服务器如Redis存储会话数据,确保数据共享。

Sessionlockingisatechniqueusedtoensureauser'ssessionremainsexclusivetooneuseratatime.Itiscrucialforpreventingdatacorruptionandsecuritybreachesinmulti-userapplications.Sessionlockingisimplementedusingserver-sidelockingmechanisms,suchasReentrantLockinJ

PHP会话的替代方案包括Cookies、Token-basedAuthentication、Database-basedSessions和Redis/Memcached。1.Cookies通过在客户端存储数据来管理会话,简单但安全性低。2.Token-basedAuthentication使用令牌验证用户,安全性高但需额外逻辑。3.Database-basedSessions将数据存储在数据库中,扩展性好但可能影响性能。4.Redis/Memcached使用分布式缓存提高性能和扩展性,但需额外配

Sessionhijacking是指攻击者通过获取用户的sessionID来冒充用户。防范方法包括:1)使用HTTPS加密通信;2)验证sessionID的来源;3)使用安全的sessionID生成算法;4)定期更新sessionID。

本文比较了PHP和ASP.NET,重点是它们对大规模Web应用程序,性能差异和安全功能的适用性。两者对于大型项目都是可行的,但是PHP是开源和无关的,而ASP.NET,


热AI工具

Undresser.AI Undress
人工智能驱动的应用程序,用于创建逼真的裸体照片

AI Clothes Remover
用于从照片中去除衣服的在线人工智能工具。

Undress AI Tool
免费脱衣服图片

Clothoff.io
AI脱衣机

Video Face Swap
使用我们完全免费的人工智能换脸工具轻松在任何视频中换脸!

热门文章

热工具

EditPlus 中文破解版
体积小,语法高亮,不支持代码提示功能

SublimeText3汉化版
中文版,非常好用

WebStorm Mac版
好用的JavaScript开发工具

ZendStudio 13.5.1 Mac
功能强大的PHP集成开发环境

SublimeText3 Mac版
神级代码编辑软件(SublimeText3)