使用 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