• 长连接


      我们经常会看到一些网站可以实时的向我们的页面推送一些信息,比如网页版的聊天、或者一些社交网站上的消息推送等等。那么怎样才能做到呢?我提供一种方法,不一定是最优解,但能实现基本的需求。

      首先我们必须说明一点:要有一些后端的知识,因为这次我们要同时写前、后端。

      我下面就以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是处理数据的程序。

    小结:

      到这里一个简单的长连接就完成了。

  • 相关阅读:
    2.7 矩阵的秩
    HDU
    HDU
    HDU
    HDU
    HDU
    hdu 5179 beautiful number(数位dp)
    ACdream
    CodeForces
    <a>标签中 href="/" 和 hideFocus="true"
  • 原文地址:https://www.cnblogs.com/webARM/p/4104173.html
Copyright © 2020-2023  润新知