Home  >  Article  >  Backend Development  >  一个iframe实现长轮询,通过PHP查询数据库并用JS更新页面内容的程序,问题是并不是每一条MYSQL的INSERT消息都能显示到页面,求帮忙分析下哪里有问题

一个iframe实现长轮询,通过PHP查询数据库并用JS更新页面内容的程序,问题是并不是每一条MYSQL的INSERT消息都能显示到页面,求帮忙分析下哪里有问题

WBOY
WBOYOriginal
2016-06-23 14:38:471298browse

本帖最后由 stneo1990 于 2013-08-08 11:45:06 编辑

首先,这是一个仿客服咨询的实时通讯系统,主要目的是将模拟前台用户发送的消息(通过手动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>在线客服系统--客服端</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的轮询方式,这种的后台查询脚本里没有主动结束脚本执行,可能存在一定问题。

我测试的是只能显示一个 后面的都显示不出来

Statement:
The content of this article is voluntarily contributed by netizens, and the copyright belongs to the original author. This site does not assume corresponding legal responsibility. If you find any content suspected of plagiarism or infringement, please contact admin@php.cn
Previous article:CURL抓取失败请教Next article:php中@property的作用?