前台页面使用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}
*/
参考: