使用 Node.JS 构建 Long Polling 应用程序
Comet是指基于HTTP长连接的“服务器推”技术,是一种新的web应用架构。基于这种架构开发的应用中,服务器端会主动以异步的方式向客户端程序推送数据,而不需要客户端显示的发出请求。非常适合股票交易行情,聊天室等交互性和实时性要求很强的应用。
长轮询(Long Polling)是Comet的一种实现方式,也是Facebook,Plurk实现动态更新内容的方法,具体原理是发送一个长时间等待的request,当服务器有资料response的时候立刻断掉,接着再发送一个新的request。
我们这里使用新浪微博的openAPI做我们的数据来源,我们需要每隔5秒中推送5条最新的微博内容到客户端,由客户端进行呈现。
我们先来看下前端部分的代码,这里使用YUI3作为基础框架。
<script type="text/javascript"> YUI().use('jsonp','node-base',function(Y){ var handler = function(response){ var s = ''; for(var i=0;i<response.length;i++){ s +='<li class="MIB_linedot_1">'; s +='<div class="head_pic"><img src="'+response[i].user.profile_image_url+'"></div>'; s +='<divm class="MIB_feed_c"><p class="sms"><a href="#">'+response[i].user.name+'</a> : '+response[i].text+'</p></div>' s +='</li>'; } Y.one('#weibo').prepend(s); Y.jsonp('http://127.0.0.1:8000/stream?callback={callback}',arguments.callee); }; Y.jsonp('http://127.0.0.1:8000/stream?callback={callback}',handler); }); </script>
我们看到在浏览器端我们使用JSONP的方式来取得服务器端的数据并执行回调,每次收到服务器端的数据并处理后会再次发起一个JSONP的请求来保持与服务器端的连接。
下面我们看下服务器端的代码是怎么样的,这里不在讲述Node.JS的基础问题,有问题的同学可以去http://nodejs.org查看相关文档和介绍。
首先需要引入Node.JS的相关API
var http = require('http'); var path = require('path'); var qs = require('querystring'); var fs = require('fs'); var url = require('url');接下来我们要创建一个客户端请求来请求微博openAPI的接口数据。
var weibo_client = http.createClient(80,'api.t.sina.com.cn');然后创建http服务,发送内容到客户端。
var server = http.createServer(function(request,response){ var uri = url.parse(request.url).pathname; var callback = qs.parse(url.parse(request.url).query).callback; console.log(callback); if(uri === '/stream'){ //定时从api得到需要的数据 setTimeout(function(){ var client_request = weibo_client.request('GET','/statuses/public_timeline.json?source=3364481477&count=5',{'host':'api.t.sina.com.cn'}); //对返回的数据进行处理 client_request.on('response',function(res){ var body = ''; res.on('data',function(data){ body += data; }); res.on("end",function(){ var weibo = JSON.parse(body); if(weibo.length > 0){ response.writeHead(200,{'Content-Type':'text/javasript'}); var text = callback + "("+JSON.stringify(weibo)+")"; console.log(text); response.write(text); response.end(); } }); }); client_request.end(); },5000); }else{ load_static_file(uri,response); } });
在上面的代码中当客户端连接到服务器端请求数据的时候,我们就每隔5秒去请求一次openAPI的接口,获取到最新的5条feed信息,通过监听 clientRequest的response事件来获得最新的数据。通过监听clientRequest的end事件对获得的数据转换为JSON格式的 字符串并推送到客户端去。
最后我们开启http服务就可以了。
1 | Server.listen(8000); |
下面是该程序的所有代码:
客户端:
<!DOCTYPE html> <html> <head> <title>weibo stream</title> <link href="http://img.t.sinajs.cn/t35/style/css/common/index.css" type="text/css" rel="stylesheet" /> <script type="text/javascript" src="http://yui.yahooapis.com/3.3.0/build/yui/yui-min.js"></script> </head> <body> <ul id="weibo" class="MIB_feed" style="width:555px;"></ul> <script type="text/javascript"> YUI().use('jsonp','node-base',function(Y){ var handler = function(response){ console.log(response); var s = ''; for(var i=0;i<response.length;i++){ s +='<li class="MIB_linedot_1">'; s +='<div class="head_pic"><img src="'+response[i].user.profile_image_url+'"></div>'; s +='<divm class="MIB_feed_c"><p class="sms"><a href="#">'+response[i].user.name+'</a> : '+response[i].text+'</p></div>' s +='</li>'; } Y.one('#weibo').prepend(s); Y.jsonp('http://127.0.0.1:8000/stream?callback={callback}',arguments.callee); }; Y.jsonp('http://127.0.0.1:8000/stream?callback={callback}',handler); }); </script> </body> </html>Server:
var http = require('http'); var path = require('path'); var qs = require('querystring'); var fs = require('fs'); var url = require('url'); //创建http client服务 var weibo_client = http.createClient(80,'api.t.sina.com.cn'); //读取静态文件 var load_static_file = function(uri,response){ var filename = path.join(process.cwd(),uri); path.exists(filename,function(exists){ if(!exists){ response.writeHeader(404,{'Content-Type':'text/plain'}); response.write('404 Not Found\n'); response.end(); return; } fs.readFile(filename,'binary',function(err,file){ if(err){ response.writeHeader(500,{'Content-Type':'text/plain'}); response.write(err + '\n'); response.end(); return; } response.writeHeader(200); response.write(file,'binary'); response.end(); }); }); }; //创建http服务 var server = http.createServer(function(request,response){ var uri = url.parse(request.url).pathname; var callback = qs.parse(url.parse(request.url).query).callback; console.log(callback); if(uri === '/stream'){ //定时从api得到需要的数据 setTimeout(function(){ var client_request = weibo_client.request('GET','/statuses/public_timeline.json?source=3364481477&count=5',{'host':'api.t.sina.com.cn'}); //对返回的数据进行处理 client_request.on('response',function(res){ var body = ''; res.on('data',function(data){ body += data; }); res.on("end",function(){ var weibo = JSON.parse(body); if(weibo.length > 0){ response.writeHead(200,{'Content-Type':'text/javasript'}); var text = callback + "("+JSON.stringify(weibo)+")"; console.log(text); response.write(text); response.end(); } }); }); client_request.end(); },5000); }else{ load_static_file(uri,response); } }); server.listen(8000);
该程序在Node.JS v0.4.6版本下测试通过。
原文出处:http://ued.sina.com/?p=801