長連接


  我們經常會看到一些網站可以實時的向我們的頁面推送一些信息,比如網頁版的聊天、或者一些社交網站上的消息推送等等。那么怎樣才能做到呢?我提供一種方法,不一定是最優解,但能實現基本的需求。

  首先我們必須說明一點:要有一些后端的知識,因為這次我們要同時寫前、后端。

  我下面就以nodeJS為例,當然其他的后端實現方法也是可以的,基本原理是一樣的。

  第一步:確定思路。

  頁面加載后向后台發送一個Ajax請求(如果對Ajax還不了解可以到W3C上學習一下,上面有很棒的講解),作為長連接的發起。當后端收到請求后,延時處理20秒后再回應前端頁面。前台收到后端響應后就立即發起下一次請求,這樣無限循環下去。就完成了長連接的基本功能。下一步我們先實現一下,完成后我們在對它進行優化。

前端:

在你的ready()里面添加如下代碼:

function longLink(){
            var data = {
                //'type': 'longLink'
            };
            $.post('/longLink', {
                data: data,
                "_csrf": token
            }, function (result) {
                //console.log('long link data: ', result);
                longLink();
            });
        }

        longLink();

我們這里使用的是POST請求。既然我們向后台發了請求,后台哪有讓老朋友吃閉門羹的道理!

后端:

用你喜歡的方式(express或kraken等等都可以)創建nodejs工程,下面在route或controller中添加你的路由處理邏輯

 1 router.post('/longLink', function (req, res) {
 2         var data = req.body.data;
 3         var curRes = res;
 4 
 5         //20秒定時鏈接 並告知瀏覽器無openid
 6         var longLinkTimeCtl = setTimeout(function(){
 7             curRes.send({
 8                 code: 0,
 9                 detail:{
10                     withData: false
11                 }
12             });  
13         }, 20000);
14 
15     });

這樣就有了一個基本的長連接。后端在req.body中拿到前端發來的數據然后再延時響應。20秒的時間可以根據自己的需求修改,如果有對前端的通知可以夾雜在send中的對象內。

 

進階:

看到nodejs(后端)send中的withData:false了嗎?作為“例行公事”的響應中,當然不會有數據啦,那么僅僅是不斷循環的請求--響應,又有什么意義呢?換句話說,什么時候發送攜帶數據的響應呢?

當我們的后端收到某個數據(其他的請求或有新來的數據,總之就是一個需要后端馬上響應前端的時機)的時候,我們就要打斷原有的延時(clearTimeout),立即響應並攜帶信息。下面我們假設這一時機是一個事件監聽:

router.post('/longLink', function (req, res) {
        var data = req.body.data;
        var curRes = res;

        //20秒定時鏈接 並告知瀏覽器無openid
        var longLinkTimeCtl = setTimeout(function(){
            curRes.send({
                code: 0,
                detail:{
                    withData: false
                }
            });  
            //解綁 防止多次綁定
            global.event_getData.removeListener('getData', getDataCallback);
        }, 20000);

        // 接到 獲取openid的事件后 打斷20秒定時 立即響應瀏覽器,並攜帶openid
        var getDataCallback = function(data){
            clearTimeout(longLinkTimeCtl);
            
            if(data.xxx){
                var xxx= data.xxx;

                curRes.send({
                    code: 0,
                    detail:{
                        withData: true,
                        data:{
                            xxx: xxx
                        }
                    }
                });
            }
            //解綁 防止多次綁定
            global.event_getData.removeListener('getData', getDataCallback);
        }

        
        global.event_getData.on('getData', getDataCallback);
    });

 假設服務器的某個邏輯收到了某個數據,碰巧我們的需求中要求我們必須馬上把這個數據發送到前端頁面,就可以在拿到數據的邏輯處觸發一個全局的事件(至於nodejs中如何處理事件,我將在下一篇文章中簡單的分享一下),這里你只要知道我們可以向jquery中那樣用on()來監聽。我的例子中事件的回調函數名為getDataCallback,記住這個名字,一會我們還要解除綁定。按照getDataCallback中邏輯,我們要在接到數據后清除延時而馬上把消息send給頁面。我想細心的你一定會發現下面這句是干什么的?而且還用了兩次。

global.event_getData.removeListener('getData', getDataCallback);

由於在長連接中前端頁面一直在不斷的向后端發請求,on()的綁定也會綁定多次,我們需要解綁來保證只綁定了一個,以防多次響應。我想一定會有人問我為什么不直接在綁定之前解綁,而是在兩個出口解綁?原因是:每一次進入路由后,我們就和上一次進入的不是同一個空間了,所以在綁定之前解綁並不能達到預期的效果,回調依然會觸發多次。我們在兩個出口解綁,可以在當前的空間解綁。

當我們發送的響應中攜帶了數據而且withData: true,剩下的工作就是前端頁面了。

 1 function longLink(){
 2             var data = {
 3                 //'type': 'longLink'
 4             };
 5             $.post('/longLink', {
 6                 data: data,
 7                 "_csrf": token
 8             }, function (result) {
 9                 //console.log('long link data: ', result);
10                 longLink();
11                 if(result.code == 0){
12                     //判斷是否攜帶了信息
13                     if(result.detail.withData){
14                         yyyyyyyyyyyy(result.detail.data);
15                     }
16                 }
17             });
18         }
19 
20         longLink();

這里yyyyyyyyyyyy是處理數據的程序。

小結:

  到這里一個簡單的長連接就完成了。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM