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