Node.js實現資料推送,node.js資料推
情境:後端更新資料推送到用戶端(Java部分使用Tomcat伺服器)。
後端推送資料的解決方案有很多,比如輪詢、Comet、WebSocket。
1. 輪詢對於後端來說開發成本最低,就是按照傳統的方式處理Ajax請求並返回資料,在學校的時候實驗室的項目一直都採用輪詢,因為它最保險也最容易實現。但輪詢帶來的通訊資源的浪費是無法忽視的,無論資料是否改變,都照常發送請求並響應,而且每次HTTP請求都帶有很長的頭部資訊。
2. Comet的概念是長串連,用戶端發送請求後,後端將串連保持下來,直到連線逾時或後端返回資料時再重建立立串連,有效將通訊資源轉移到了伺服器上,實際消耗的是伺服器資源。
3. WebSocket是HTML5提供的一種全雙工系統通訊技術,通過“握手”實現用戶端與伺服器之間的通訊,即時性好,攜帶的頭部也較小,目前支援的瀏覽器如下:
理想的情況是採取WebSocket與Comet結合的方式,對IE8等瀏覽器採取Comet方式,做降級處理。但是這樣一來,後端需要實現兩種處理請求的邏輯,即WebSocket與Comet。所以,本文加入Node.js,之所以這樣做,是將處理WebSocket(或Comet)的邏輯轉移到Node.js部分,不給後端“添麻煩”,因為在實際情況下,前端開發人員推動後端開發人員並不容易。Node.js作為瀏覽器與Java商務邏輯層通訊的中介層,串連用戶端與Tomcat,通過Socket與Tomcat進行通訊(是Socket,不是WebSocket,後端需要實現Socket介面。
在用戶端,WebSocket與Comet通過Socket.io實現,Socket.io會針對不同的瀏覽器版本或者不同用戶端選擇合適的實現方式(WebSocket, long pull..),Socket.io的引入讓處理WebSocket(或長串連)變的很容易。Socket.io
用戶端引入socket.io:
<script src="static/js/socket.io.js"></script>
用戶端JavaScript代碼:
var socket = io.connect('127.0.0.1:8181'); // 發送資料至伺服器socket.emit('fromWebClient', jsonData);// 從伺服器接收資料 socket.on('pushToWebClient', function (data) { // do sth. });
Node.js伺服器代碼:
var http = require('http'), app = http.createServer().listen('8181'), io = require('socket.io').listen(app); io.sockets.on('connection', function (socketIO) { // 從用戶端接收資料 socketIO.on('fromWebClient', function (webClientData) { // do sth. }); // 用戶端中斷連線 socketIO.on('disconnect', function () { console.log('DISCONNECTED FROM CLIENT'); }); // 向用戶端發送資料 socketIO.emit('pushToWebClient', jsonData); });
建立好用戶端同Node.js伺服器的串連只是第一步,下面還需要建立Node.js伺服器與Java商務邏輯層的聯絡。這時,Node.js伺服器則作為用戶端,向Tomcat發送TCP串連請求。串連成功後,Node.js伺服器和Tomcat建立了一條全雙工系統的通道,而且是唯一的一條,不論有多少個用戶端請求,都從Node.js伺服器轉寄至Tomcat;同樣,Tomcat推送過來的資料,也經由Node.js伺服器分發至各個用戶端。
這裡存在一個問題,就是在WebSocket串連與Socket串連都建立好之後,兩次串連彼此之間是屏蔽的。Tomcat不知道是哪次WebSocket串連發送過來的資料,也不知道是哪個用戶端發來的資料。當然,Node.js可以利用session id發送至Tomcat來標識是哪一個用戶端,但本文採用的是另外一種辦法。
用戶端同Node.js建立WebSocket串連時,每個串連都會包含一個執行個體,這裡稱它為socketIO。每個socketIO都有一個id屬性用來唯一標識這個串連,這裡稱它為socket_id。利用socket_id,在Node.js伺服器建立一個映射表,儲存每一個socketIO與socket_id的映射關係。Node.js伺服器發送資料給Tomcat時帶上這個socket_id,再由Java部分進行一系列處理以後封裝好每個用戶端需要的不同資料一併返回,返回的資料裡要有與socket_id的對應關係。這樣,Node.js伺服器收到Tomcat發來的資料時,通過前面提到的映射表由不同的socketIO分發至不同的用戶端。
Node.js伺服器代碼:
var http = require('http'), net = require('net'), app = http.createServer().listen('8181'), io = require('socket.io').listen(app), nodeServer = new net.Socket(); // 串連到Tomcat nodeServer.connect(8007, '127.0.0.1', function() { console.log('CONNECTED'); });// 儲存用戶端的WebSocket串連執行個體 var aSocket = {}; // 同用戶端建立串連 io.sockets.on('connection', function (socketIO) { // 從用戶端接收資料,然後發送至Tomcat socketIO.on('fromWebClient', function (webClientData) { // 儲存至映射表 aSocket[socketIO.id] = socketIO; // 發送至Tomcat的資料中添加socket_id webClientData['sid'] = socketIO.id; // 發送String類型的資料至Tomcat nodeServer.write(JSON.stringify(webClientData)); }); // 用戶端中斷連線 socketIO.on('disconnect', function () { console.log('DISCONNECTED FROM CLIENT'); }); }); // 從Tomcat接收資料 nodeServer.on('data', function (data) { var jsonData = JSON.parse(data.toString()); // 分發資料至用戶端 for (var i in jsonData.list) { aSocket[jsonData.list[i]['sid']].emit('pushToWebClient', jsonData.list[i].data); } });
上面的代碼省略了一些邏輯,比如Node.js伺服器從Tomcat接收的資料分為兩種,一種是推送過來的資料,另外一種是響應請求的資料,這裡統一處理推送過來的資料。
在處理通訊時,Node.js發送至Tomcat的資料是String格式,而從Tomcat接收的資料為Buffer對象(8進位),需要轉化為String之後再轉化為json發送至用戶端。
本文只是給出一個這樣兩次串連的簡單例子,具體的業務中需要加入許多東西。既然在項目中引入了Node.js,就需要前端承擔更多的事情,比如對資料的處理、緩衝、甚至加入很多商務邏輯。
您可能感興趣的文章:
- 資料庫複寫效能測試 推送模式效能測試
- .net 通過URL推送POST資料具體實現
- SQL Server 2000向SQL Server 2008 R2推送資料圖文教程
- JavaScript資料推送Comet技術詳解