最近公司分配任务说要做APP的扫描二维码实现网页登录,查看了一系列的文章
传送门
:微信二维码登录的原理
感谢作者的无私分享,提供了基本思路后,我开始纠结了.
打开网页版微信,Chrome的timeline里面,我看到长轮询这个以前一直都迷迷糊糊的概念,没办法主管分派了任务死也要死出来.本来想着用个JS的setInterval算了. 谁叫我是天蝎座的命, 处女座的病! (扫描二维码网页登录的例子后面送上!)
看重点! 这里只讲轮询!
没办法硬着头皮查找长轮询的资料吧~ 文字较多,耐心看看希望对你们有帮助
传送门
:Web 通信 之 长连接、长轮询(long polling)
看了很多,觉得以上文章是最好的.里面说到轮询会出现的情况(文字功底不好只能拿来主意):
-
轮询的建立
建立轮询的过程很简单,浏览器发起请求后进入循环等待状态,此时由于服务器还未做出应答,所以HTTP也一直处于连接状态中。 -
数据的推送
在循环过程中,服务器程序对数据变动进行监控,如发现更新,将该信息输出给浏览器,随即断开连接,完成应答过程,实现“服务器推”。 -
轮询的终止,轮询可能在以下3种情况时终止:
- 有新数据推送
当循环过程中服务器向浏览器推送信息后,应该主动结束程序运行从而让连接断开,这样浏览器才能及时收到数据。 - 没有新数据推送
循环不能一直持续下去,应该设定一个最长时限,避免WEB服务器超时(Timeout),若一直没有新信息,服务器应主动向浏览器发送本次轮询无新信息的正常响应,并断开连接,这也被称为“心跳”信息。 - 网络故障或异常
由于网络故障等因素造成的请求超时或出错也可能导致轮询的意外中断,此时浏览器将收到错误信息。
- 有新数据推送
-
轮询的重建
浏览器收到回复并进行相应处理后,应马上重新发起请求,开始一个新的轮询周期。
我在长轮询编码时遇到的坑
首先, 就是PHP后端的问题, 在轮询的时候后端会用while(true)的形式, 来hold住这个Ajax请求, 让他迟迟不能获得数据, 一旦获取数据前端Ajax立马就会做出飞一般的反应(网络好的时候确实飞呀飞~).
但是别太乐观, 一旦我们的前端终止了请求, 那么服务端PHP就无限的循环下去, 他不会终止了! 伴随着ignore_user_abort(true)
和set_limit_time(0)
这个程序会很欢快的跑下去, 而且你会发现你的其他业务都会因为这样而停止!
你妈妈的吻~
查询了一些资料后, 是因为session处于被锁的状态.所以导致了其他页面也跟着不能正常了.解决方案:
session_write_close()
, 页面总算正常了.
只不过呢? 程序还是欢快的在后台放羊般的执行着, 而且你还不知道, 知道笔记本发热你才会觉察.
这个时候我就在想, 有没有一个PHP函数可以让PHP知道前端已经断开了, 让死循环终止吧~
结果一Google~ 真有!!! 当当当当~~
connection_aborted() //就是他! 返回值: 未断开为false 断开为true
有了这个我们就可以在客户端断开\关闭浏览器\Ajax超时执行的时候自动终止程序了.说了这么多, 感觉还是来看看代码吧.光说不练假把式~
代码时间:
这个代码只是一个测试例子, 测试效果是否被实现, 读者可以自行修改.
首先, 是前端HTML代码:
<html lang="en">
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Document</title>
<script type="text/javascript" src="./jquery1.4.2.js"></script>
<script type="text/javascript">
$(function () {
var MsgBox = {
MsgObj: $('#msg'),
showMsg: function (msg) {
MsgBox.MsgObj.html(msg);
}
}
//轮询
var Comet = {
Init: function () {
$('#btn').unbind();
$('#btn').bind('click', Comet.Poll);
},
//轮询
Poll: function () {
//为了打日志写的东西,随机生成的
var id = parseInt(Math.random() * 1000);
MsgBox.showMsg('');
$.ajax({
url: './test.php', //访问地址
type: 'post', //post方式提交
data: {id: id}, //传入ajax数据
dataType: 'json', //返回格式
timeout: 10000, //超时设置三十秒
success: Comet.Success, //成功时的返回
error: Comet.Failed //失败的时候
});
},
//成功获取数据时
Success: function (data) {
if (data.status == 1) {
MsgBox.showMsg(data.info);
}
},
//没有获取数据
Failed: function (XMLHttpRequest, textStatus, errorThrown) {
//超时重新连接
if (textStatus == 'timeout') {
Comet.Poll();
} else {
Comet.Poll();
}
}
};
Comet.Init();
});
</script>
</head>
<body>
<div id="msg"></div>
<input type="button" value="开始" id="btn">
</body>
</html>
这部分代码只是让前端在点击开始后,不断的Ajax提交访问请求, 添加了超时时间, 让Ajax可以在超时时候中断连接, 然后通过错误处理重新启动, 用递归来做循环吧(我的理解), 这个没有什么难度. 其实技术说穿了都那样白菜价.
然后是,Ajax请求中的test.php:
<?php
//让脚本无限制执行下去
set_time_limit(0);
ignore_user_abort(true);
session_write_close();
$i=1;
while(true){
//未断开连接就处理嘛
if(!connection_aborted()){
sleep(1);
if($i >= 50) {
echo json_encode(array('status'=>1, 'info'=>'lalalala'));
break;
}
$i++;
}
}
//断了连接,我就记录下,为了调试效果是否成功! 实际中看情况使用
if(!connection_aborted()){
echo json_encode(array('status'=>1, 'info'=>'停止了'));
file_put_contents('stop.txt',"stop:".$_POST['id'].'-----'.date('Y-m-d H:i:s')."\n", FILE_APPEND);
exit();
}
温馨提示:
HTML的代码里面jQuery库请自行添加, 我就不提供了.
在你点击了前端的"开始"后, 请注意我们的Chrome中的时间线, 我设置了十秒超时, 所以你每隔10s就可以看到一个新的Ajax请求去访问后端PHP, 而后端有没有终止, 你只需要在Linux下的用tail -f stop.txt
这个日志文件就可以看到实时的日志变化.
加个小广告: 有程序员直男或程序员妹子想用好面膜的话, 站内信我留下你们的QQ或微信我会加你们的,呵呵~~