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