新浪UED

使用Node.JS构建Long Polling应用程序

by Fisher Ma / 前端开发,博客 / 2011-10-14
使用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服务就可以了。

Server.listen(8000);

下面是该程序的所有代码:

Client:

<!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 Foundn');
			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版本下测试通过。

文章评论

  1. 博主太有才了

  2. 匿名 说:

    这样并不能减少 服务器端的压力啊,还是每隔5秒取一次

  3. 快播网 说:

    我也下了,哈哈,测试通过……..

  4. 终小南 说:

    不错,回头我也测试一下。

  5. 小爝 说:

    你这个方法和ajax请求随便搞个jsp,php写没什么区别,客户端也没用到socket,后端还加重了负担。

    直接会把服务器搞死的。。这不过是实现了一个定时取数据的nodejs写成的server服务。。也不是long Polling啊……代码和标题感觉有出入。

  6. 美文 说:

    祝博主2012年快乐。
    辛卯年(兔)腊月廿一 2012-1-14

  7. KissCss 说:

    这篇很给你。新浪微博不会是这样架构的吧。

  8. 洋洋 说:

    写得很好。。

  9. 匿名 说:

    这个应该算是定时器把?和长轮询有关系?

  10. 康康 说:

    我觉得应该是这个例子有问题,我们可以假设一个情景:两个微博用户之间互相关注,那么在两个用户看微博的过成功,用户A任何的转载,评论甚至收藏都可以被服务器端自动推送到用户B这里,这样也许才可以体现出NodeJs的优势吧。

  11. 阿园园 说:

    写的挺好的。。。。

  12. 匿名 说:

    程式碼似曾相識

  13. 洪哥爱骑自行车 说:

    哪里有推啊,还是前台页面,每5秒请求一次获取数据啊。
    不就是异步请求吗?
    这个”推”,迷惑了我好长时间。

发表评论

电子邮件地址不会被公开。 必填项已用*标注

* 验证图片 刷新验证码

您可以使用这些HTML标签和属性: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>