node.js实现的Long Polling例子

前台页面使用jquery的jsonp来进行轮询。后端node.js监听的端口是8124

index.html

<!Doctype html>
<html>
<head>
<title>Long Polling in node.js</title>
<meta http-equiv='content-type' content='text/html; charset=utf-8'>
<style type='text/css'>
* {margin:0; padding:0;}
body {background-color:#fff;}

#infoContainer{margin:40px; padding:10px; font-size:14px; border:1px solid #eee;}
</style>
</head>
<body>

<div id='infoContainer'>loading...</div>

<script type='text/javascript' src='js/jquery.js'></script>
   1:  
   2:  
   3: <script type='text/javascript'>
   4:  
   5: function callPolling() {
   6:     $.ajax({
   7:         url: 'http://localhost:8124/?callback=pollingCallback',
   8:         dataType : 'jsonp',
   9:         jsonp : 'kk',
  10:         timeout : 70 * 1000,
  11:         complete : function() {
  12:             callPolling();
  13:         }
  14:     })
  15: }
  16:  
  17: function pollingCallback(str) {
  18:     $("#infoContainer").html(str);
  19: }
  20:  
  21: $(callPolling);
  22:  
</script>

</body>
</html>

后台用node.js实现的polling.js

 

var http = require('http'),
    fs = require('fs');
 
http.createServer(function(req, res) {
    checkFile(req, res);
}).listen(8124);
 
var filepath = 'E:/Node_app/file/a.txt';
 
function checkFile(req, res) {
    var reqUrl = req.url;
    var callbackFnName = null;
 
    if (/callback=([^&]+)/.test(reqUrl)) {
        callbackFnName = RegExp['$1'];
    }
 
    var date = new Date();
 
    if (date - req.socket._idleStart.getTime() > 60 * 1000) {
        res.writeHead(200, {
            'Content-Type' : 'text/plain',
            'Access-Control-Allow-Origin' : '*'
        });
 
        res.write(callbackFnName + "('ok')", 'utf8');
        res.end();
    }    
 
    fs.stat(filepath, function(err, stats) {
        if (err) {
            res.writeHead(200, {
                'Content-Type' : 'text/plain',
                'Access-Control-Allow-Origin' : '*'
            });
 
            res.write(callbackFnName + "('Error')", 'utf8');
            res.end();
 
            return false;
        }
 
        //文件是在请求过来之后发生更改的
        if (stats.mtime.getTime() > req.socket._idleStart.getTime()) {
            fs.readFile(filepath, 'utf8', function(err, data) {
                res.writeHead(200, {
                    'Content-Type' : 'text/plain',
                    'Access-Control-Allow-Origin' : '*'
                });
 
                res.write(callbackFnName + "('" + data + "')", 'utf8');
                res.end();
 
                return false;
            });
        }
    });
    
    setTimeout(function() {
        checkFile(req, res);        
    }, 10 * 1000);
}
 
/**
 * 时间对象的格式化;
 */
Date.prototype.format = function (format) {
    /*
     * eg:format="YYYY-MM-dd hh:mm:ss";
     */
    var o = {
        "M+": this.getMonth() + 1, //month
        "d+": this.getDate(), //day
        "h+": this.getHours(), //hour
        "m+": this.getMinutes(), //minute
        "s+": this.getSeconds(), //second
        "q+": Math.floor((this.getMonth() + 3) / 3), //quarter
        "S": this.getMilliseconds() //millisecond
    }
 
    if (/(Y+)/i.test(format)) {
        format = format.replace(RegExp.$1, (this.getFullYear() + "").substr(4 - RegExp.$1.length));
    }
 
    for (var k in o) {
        if (new RegExp("(" + k + ")").test(format)) {
            format = format.replace(RegExp.$1, RegExp.$1.length == 1 ? o[k] : ("00" + o[k]).substr(("" + o[k]).length));
        }
    }
    return format;
}
 
setInterval(function() {
    fs.writeFileSync(filepath, '当前时间:' + new Date().format('YYYY-MM-dd hh:mm:ss'), 'utf8');    
}, 1000 * 1);

 

监听文件发生改变,就立即输出内容给前台页面请求。

这里有关于文件atime、ctime、mtime三者区别的详细介绍>>

关于File的元信息,可以参考这里(stat详解)>>

 

在控制台上打印出的req信息

{
    socket: {
        _handle: {
            writeQueueSize: 0,
            owner: [Circular],
            onread: [Function: onread]
        },
        _pendingWriteReqs: 0,
        _flags: 0,
        _connectQueueSize: 0,
        destroyed: false,
        errorEmitted: false,
        bytesRead: 602,
        _bytesDispatched: 0,
        allowHalfOpen: true,
        writable: true,
        readable: true,
        _paused: false,
        server: {
            _connections: 1,
            connections: [Getter / Setter],
            allowHalfOpen: true,
            _handle: [Object],
            _events: [Object],
            httpAllowHalfOpen: false,
            _connectionKey: '4:0.0.0.0:8124'
        },
        _events: {
            drain: [Function: ondrain],
            timeout: [Object],
            error: [Function],
            close: [Object]
        },
        _idleTimeout: 120000,
        _idleNext: {
            _idleNext: [Circular],
            _idlePrev: [Circular],
            ontimeout: [Function]
        },
        _idlePrev: {
            _idleNext: [Circular],
            _idlePrev: [Circular],
            ontimeout: [Function]
        },
        _idleStart: Tue Jul 24 2012 01: 18: 39 GMT + 0800(中国标准时间),
        parser: {
            _headers: [],
            _url: '',
            onHeaders: [Function: parserOnHeaders],
            onHeadersComplete: [Function: parserOnHeadersComplete],
            onBody: [Function: parserOnBody],
            onMessageComplete: [Function: parserOnMessageComplete],
            socket: [Circular],
            incoming: [Circular],
            maxHeaderPairs: 2000,
            onIncoming: [Function]
        },
        ondata: [Function],
        onend: [Function],
        _httpMessage: {
            output: [],
            outputEncodings: [],
            writable: true,
            _last: false,
            chunkedEncoding: false,
            shouldKeepAlive: true,
            useChunkedEncodingByDefault: true,
            sendDate: true,
            _hasBody: true,
            _trailer: '',
            finished: false,
            socket: [Circular],
            connection: [Circular],
            _events: [Object]
        }
    },
    connection: {
        _handle: {
            writeQueueSize: 0,
            owner: [Circular],
            onread: [Function: onread]
        },
        _pendingWriteReqs: 0,
        _flags: 0,
        _connectQueueSize: 0,
        destroyed: false,
        errorEmitted: false,
        bytesRead: 602,
        _bytesDispatched: 0,
        allowHalfOpen: true,
        writable: true,
        readable: true,
        _paused: false,
        server: {
            _connections: 1,
            connections: [Getter / Setter],
            allowHalfOpen: true,
            _handle: [Object],
            _events: [Object],
            httpAllowHalfOpen: false,
            _connectionKey: '4:0.0.0.0:8124'
        },
        _events: {
            drain: [Function: ondrain],
            timeout: [Object],
            error: [Function],
            close: [Object]
        },
        _idleTimeout: 120000,
        _idleNext: {
            _idleNext: [Circular],
            _idlePrev: [Circular],
            ontimeout: [Function]
        },
        _idlePrev: {
            _idleNext: [Circular],
            _idlePrev: [Circular],
            ontimeout: [Function]
        },
        _idleStart: Tue Jul 24 2012 01: 18: 39 GMT + 0800(中国标准时间),
        parser: {
            _headers: [],
            _url: '',
            onHeaders: [Function: parserOnHeaders],
            onHeadersComplete: [Function: parserOnHeadersComplete],
            onBody: [Function: parserOnBody],
            onMessageComplete: [Function: parserOnMessageComplete],
            socket: [Circular],
            incoming: [Circular],
            maxHeaderPairs: 2000,
            onIncoming: [Function]
        },
        ondata: [Function],
        onend: [Function],
        _httpMessage: {
            output: [],
            outputEncodings: [],
            writable: true,
            _last: false,
            chunkedEncoding: false,
            shouldKeepAlive: true,
            useChunkedEncodingByDefault: true,
            sendDate: true,
            _hasBody: true,
            _trailer: '',
            finished: false,
            socket: [Circular],
            connection: [Circular],
            _events: [Object]
        }
    },
    httpVersion: '1.1',
    complete: true,
    headers: {
        accept: 'image/gif, image/jpeg, image/pjpeg, image/pjpeg, application/x-shockwave-flash, application/x-silverlight, application/vnd.ms-excel, application/vnd.ms-powerpoint, application/msword, application/x-ms-application, application/x-ms-xbap, application/vnd.ms-xpsdocument, application/xaml+xml, */*',
        'accept-language': 'zh-cn',
        'user-agent': 'Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 5.1; Trident/4.0; GTB6; QQDownload 715; .NET CLR 2.0.50727; CIBA; .NET CLR 3.0.04506.648; .NET CLR 3.5.21022)',
        'accept-encoding': 'gzip, deflate',
        host: 'localhost:8124',
        connection: 'Keep-Alive'
    },
    trailers: {},
    readable: false,
    _paused: false,
    _pendings: [],
    _endEmitted: true,
    url: '/?callback=abc&abc=1123',
    method: 'GET',
    statusCode: null,
    client: {
        _handle: {
            writeQueueSize: 0,
            owner: [Circular],
            onread: [Function: onread]
        },
        _pendingWriteReqs: 0,
        _flags: 0,
        _connectQueueSize: 0,
        destroyed: false,
        errorEmitted: false,
        bytesRead: 602,
        _bytesDispatched: 0,
        allowHalfOpen: true,
        writable: true,
        readable: true,
        _paused: false,
        server: {
            _connections: 1,
            connections: [Getter / Setter],
            allowHalfOpen: true,
            _handle: [Object],
            _events: [Object],
            httpAllowHalfOpen: false,
            _connectionKey: '4:0.0.0.0:8124'
        },
        _events: {
            drain: [Function: ondrain],
            timeout: [Object],
            error: [Function],
            close: [Object]
        },
        _idleTimeout: 120000,
        _idleNext: {
            _idleNext: [Circular],
            _idlePrev: [Circular],
            ontimeout: [Function]
        },
        _idlePrev: {
            _idleNext: [Circular],
            _idlePrev: [Circular],
            ontimeout: [Function]
        },
        _idleStart: Tue Jul 24 2012 01: 18: 39 GMT + 0800(中国标准时间),
        parser: {
            _headers: [],
            _url: '',
            onHeaders: [Function: parserOnHeaders],
            onHeadersComplete: [Function: parserOnHeadersComplete],
            onBody: [Function: parserOnBody],
            onMessageComplete: [Function: parserOnMessageComplete],
            socket: [Circular],
            incoming: [Circular],
            maxHeaderPairs: 2000,
            onIncoming: [Function]
        },
        ondata: [Function],
        onend: [Function],
        _httpMessage: {
            output: [],
            outputEncodings: [],
            writable: true,
            _last: false,
            chunkedEncoding: false,
            shouldKeepAlive: true,
            useChunkedEncodingByDefault: true,
            sendDate: true,
            _hasBody: true,
            _trailer: '',
            finished: false,
            socket: [Circular],
            connection: [Circular],
            _events: [Object]
        }
    },
    httpVersionMajor: 1,
    httpVersionMinor: 1,
    upgrade: false
}

 

参考:

1、Long Polling in node.js

2、Diving into Node.js – A Long Polling Example

3、Node.js File System 文件系统模块

posted @ 2012-07-24 02:13  meteoric_cry  阅读(2387)  评论(0编辑  收藏  举报