javascript轮询请求服务器

抛出问题:web浏览器如何与服务保持通信?

方法一:Ajax轮询

方法二:EventSource轮询

方法三:websocket保持长连接

下面的解决方案是,Ajax轮询与EventSource轮询的合体。

客户端代码:

<!DOCTYPE html>
<html>
<head>
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
    <title></title>
    <script src="jquery.min.js"></script>
    <script src="PollSource.js"></script>
</head>
<body>
    <h1>Server Data:</h1>
    <div id="serverData"></div>
    <a href="javascript:Poll.open(1000);">open poll</a>
    <a href="javascript:Poll.close();">close poll</a>
    <script type="text/javascript">
        var serverData,Poll;
        var SERVER_URL = "index.php";
        window.onload = function(){
            serverData = document.getElementById("serverData");
            Poll = new PollSource(SERVER_URL);
            Poll.onmessage = function(json) {
                //console.log(json);
                serverData.innerHTML = json.data;
            }
        }
    </script>
</body>
</html>

 PollSource.js代码:

/**
 * PollSource javascript轮询服务器
 * @param string url       服务器地址 例:www.example.com/index.php
 * @param json jsonParam 传递给服务器的参数
 * @author Echo
 */
function PollSource(url,jsonParam) {
    this.url = url;
    this.onmessage = null;
    this.resource = null;
    this.PollType = typeof(EventSource)=='undefined' ? 'AjaxGet' : 'EventSource';
    //将轮询类型传递给服务器,以便服务器作出响应
    if(typeof jsonParam == 'object') {
        jsonParam['PollType'] = this.PollType;
    }else{
        jsonParam = {PollType:this.PollType};
    }
    this.url += '?';
    for(var i in jsonParam) {
      this.url += i+'='+jsonParam[i]+'&';   
    }
    this.url = this.url.substring(0,(this.url.length-1));
    /**
     * 开始轮询
     */
    this.open = function() {
        var onmessage = this.onmessage;
        var url = this.url;
        var msg = '连接没有被建立,或者已经关闭,或者发生了某个致命错误'; //错误时不友好提示 :) 
        if(this.PollType == 'AjaxGet') {
            //采用轮询
            this.resource = {};
            url += '&Seconds=';
            var hangUp = false; //是否挂起
            var retry = spend = 3000; //最快轮询速度 3 秒一次
            this.resource.lockInt = setInterval(function(){
                retry -= spend;
                //alert(retry);
                if(retry > 0 || hangUp) return;
                hangUp = true; //挂起
                $.get(url+(new Date()).getSeconds(),{},function(data){
                    try{
                        var json = JSON.parse(data);
                        retry = json.retry;
                        hangUp = false; //取消挂起
                        if(typeof onmessage == 'function') onmessage(json);
                    }catch(e){console.log(e);alert(msg);}
                });
            },spend);
            this.resource.close = function() {
                if(typeof this.lockInt == 'number') {
                    clearInterval(this.lockInt);
                }
            }
        }else{
            //采用服务器发送事件技术
            this.resource = new EventSource(this.url);
            this.resource.onmessage = function(e) {
                try{
                    var json = JSON.parse(e.data);
                    if(typeof onmessage == 'function') onmessage(json);
                }catch(e){
                    console.log(e);alert(msg);
                }
            }
            this.resource.onerror = function(e) {
                if(this.readyState == 2) alert(msg);
            }
        }
    }
    /**
     * 关闭轮询
     */
    this.close = function() {
        if(this.resource) this.resource.close();
    }
}

服务端代码:

<?php
header("Content-type: text/html; charset=utf-8");
date_default_timezone_set("Asia/Shanghai");
$retry = 9000; //AjaxGet 轮询 最快是 3000 所以这里设置的值最好是 3 的倍数 如果不是三的倍数 那么时间误差在1~2秒内
$result = array('code'=>0,'msg'=>'拉取成功','retry'=>$retry,'data'=>'当前时间是:'.date('Y-m-d H:i:s'));
$result = json_encode($result);
$PollType = isset($_GET['PollType']) ? trim($_GET['PollType']) : '';
sleep(3); //延迟 3秒 返回数据 重试时间 9秒 刚好是 客户端12秒一次刷新数据 
if($PollType == 'AjaxGet') {
    //header('Content-Type:application/json; charset=utf-8');
    echo $result;
}else if($PollType == 'EventSource') {
    header('Content-Type: text/event-stream');
    echo 'data:'.$result."\n\n";
    echo 'retry:'.$retry."\n\n"; //EventSource轮询速度 虽然可以设定为 1 秒 一次 但不建议 
    flush();
}else{
    die('error');
}

测试效果:

代码下载:百度网盘

参考资源:

https://developer.mozilla.org/zh-CN/docs/Server-sent_events/EventSource
https://developer.mozilla.org/zh-CN/docs/Server-sent_events/Using_server-sent_events#Event_stream_format

 

posted @ 2015-11-28 18:12  扬空  阅读(1804)  评论(0编辑  收藏  举报