总体思路如下:
利用ajax请求服务器数据,当服务器没有数据的时候,一直循环不返回值,使得ajax状态一直保持等候返回消息的状态,保持长连接的效果;当服务器有数据要推送时,ajax接收后执行DOM操作,设置一个setTimeout(,1000)保证能再次请求服务器进入消息等候状态,如此保证了轮询的效果
总体结构分为两部分:1、前台客服页面(包括JS操作DOM显示消息,AJAX发送回复消息及查询请求,以及整体页面框架)
2、后台查询页面(包括查询数据库,连接时长限制以及返回查询结果并退出脚本)
还是先说后台查询程序query.php吧:
相比于通过iframe来保持长连接的查询,通过ajax请求有一个最大的特点,就是每当query.php查询并返回一条记录后,query.php可以自己终结脚本的继续运行,这样可以通过sleep()或者setTimeout()来节省资源,并且也解决了可能存在部分消息不能被及时更新的问题,可以说是最优的选择方案
那么query.php是如何执行的?
主体结构仍然是通过构造查询SQL语句,然后获得结果并用json_encode()转换后发送到前台去,但与iframe的方式有两点不同:
1、利用ajax实现的长轮询中,query.php不需要设置强制缓存输出,也就是当它查询到了结果,echo后,会立即exit()结束脚本,此时脚本终结,数据马上输出到浏览器前台,因此就不需要ob_flush()和flush()来强制输出了。这样也同时解决了在iframe中存在的之前脚本并没有结束的问题
2、query.php不需要依赖调用某个前台的JS函数,它是通过ajax返回的,也就是说它与前台页面的关联度相对独立,这样的话消息捕捉是通过ajax返回的,在JS的函数调用上就基本上不会存在捕捉丢失的问题
再说前台页面kefu.html:
这个页面其它的也是与iframe大致相同,不同的地方在于:
1、它请求后台服务器query.php是用的ajax来请求,并通过监听ajax的状态来捕捉返回值,并通过DOM操作页面
2、页面中没有iframe,因此页面不会显示为一直在“运行中”的状态
那么前台kefu.html是如何执行的?
它主要有两个功能:
1、通过ajax接收服务器的推送消息,并操作DOM更改页面显示,然后设置setTimeout()再次调用自身
2、通过AJAX POST方式发送消息到服务器并插入数据库中
关键技术点在于:
其中通过ajax接收服务器推送消息,需要在页面加载完成后就立即执行一次,并且,需要在这个函数中重复调用ajax请求方法,这样才能保证在接收到一条消息后,能马上再次进入监听消息状态。
最后,利用ajax实现长轮询的好处是很明显的:
1、可以在前台ajax请求中,设置setTimeout(,1000)来指定查询间隔时间,防止资源消耗过大(这也是为什么不采用直接调用ajax自身的原因,因为如果在接收完毕后直接调用ajax本身,那么这中间的速度太快,不光会造成资源消耗,而且还可能会造成数据错位,所以需要设定一个延时)
2、由于后台query.php程序每查询到一条记录后,会自己结束脚本运行,这样就能防止因为脚本没有被及时终结而造成的数据读取错误,并且也可以设置一个sleep(1)来降低资源消耗和查询速度。
所以,资源是可控的,消息读取也是准确的,如此来看,利用ajax完成长轮询确实是一个非常好的选择。