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

1
JavaScript Java HTML JSON C/C++ 15242 次浏览

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

请尽量让自己的答案能够对别人有帮助

15个答案

默认排序 按投票排序