• 长轮询实现消息推送


    一、应用场景
    浏览器与服务器之间保持一个长连接(http链接),服务器有最新的数据生成时及时推送到前端展现。典型场景:新邮件到达通知。
     
    二、业界常用的解决方案
    定时轮询,长轮询,websocket(HTML5新增的能力)
    其中长轮询兼容性较好,应用的较为广泛,但是切忌在移动网络中应用该技术。
     
    三、长连接前端代码
    /**
     *pns模型层
     *@constructs M2012.Model.Pns.PnsModel
     *@extends Backbone.Model
     *@example
     *new M2012.Model.Pns().startRequestPns();
     */
    M139.namespace("M2012.Model.Pns", {
        PnsModel : Backbone.Model.extend({
            callApi : M139.RichMail.API.call,
            pnsUrl : '/pns/poll?sid=' + top.sid + '&comeFrom=1003', // PNS接口地址负责推送消息到前端
            pnsErrorInterval : 1000 * 120, // 接口报错后下一次重新调接口的时间间隔
            pnsTimer : null, // 接口报错后需要用定时器再调一次接口,pnsTimer用于报错定时器ID
            msgTypes : {//pns推送过来的消息类型
                mailMsg : 70
            },
            logger : new top.M139.Logger({
                name : "M2012.Model.Pns"
            }),
            initialize : function() {
                $App.registerModel("pnsModel", this);
            },
    
            startRequestPns : function() {
                var self = this;
    
                var options = {};
                options.method = 'get';
                options.timeout = self.pnsErrorInterval;
                options.error = function() {
                    self.callPns();
                    self.logger.error("newMailArrival callPns error");
                };
                options.ontimeout = function() {
                    self.callPns();
                    self.logger.error("newMailArrival callPns timeout");
                };
                options.isSendClientLog = false;
    
                M139.RichMail.API.call(self.pnsUrl, null, function(e) {
                    var result = e.responseData;
                    if (result) {
                        console.log(result);
                        if (result.errorCode) {
                            self.callPns();
                            self.logger.error("newMailArrival returndata error", "[pns/poll]", result);
                        } else {
                            self.pnsResultHandle(result);
                            $App.trigger("pnsNewArrival", result);
                            //留给以后扩展
                            self.callPns(500);
                            //self.autoReceiveMail();
                        }
                    } else {
                        self.callPns();
                        self.logger.error("newMailArrival returndata error", "[pns/poll]", result);
                    }
                }, options);
            },
    
            callPns : function(seconds) {
                var self = this;
    
                // 判断用户是否登录超时
                if (top.$App.isSessionOut()) {
                    console.log('登录超时!不再请求PNS');
                    return;
                }
    
                if (self.pnsTimer) {
                    clearTimeout(self.pnsTimer);
                }
                self.pnsTimer = setTimeout(function() {
                    self.startRequestPns();
                }, seconds || self.pnsErrorInterval);
            },
    
            /*
             * 此函数可用于单元测试
             * $App.getModel("pnsModel").pnsResultHandle({});
             */
            pnsResultHandle : function(result) {
                var self = this;
                if (result.c > 0) {//c代表数量
                    var msgArr = result.msg;
                    for (var i = 0, l = msgArr.length; i < l; i++) {
                        // TODO 根据消息类型处理业务逻辑
                    }
                } else if (result.c == 0) {
                    console.log('超时返回!autoReceiveMail');
                }
            }
        })
    });
     
    四、异常捕获及应用服务器
    (1)客户端捕获到xhr的error事件或者接口超时之后可500毫秒之后开始下次轮询。
    (2)服务端接口报错,不要立即开始下次轮询,可考虑2分钟甚至更长时间后再开始轮询,因为服务端通常需要较长时间恢复正常。
    (3)服务端要保持大量的长连接通常需要用特殊的应用服务器,比如:jetty 。tomcat是肯定不行的。
     
    五、参考资料
    书籍:《web性能权威指南》
    竞品:163邮箱收信
     
  • 相关阅读:
    Linux日志文件utmp、wtmp、lastlog、messages
    Linux日志五大命令详解
    php 函数合并 array_merge 与 + 的区别
    MySQL对数据表进行分组查询(GROUP BY)
    如何在mysql中查询每个分组的前几名
    Autojump:一个可以在 Linux 文件系统快速导航的高级 cd 命令
    linux 查看磁盘空间大小
    js刷新页面方法大全
    [知乎有感] 读研到底为了什么,值不值得?
    [Hadoop] 在Ubuntu系统上一步步搭建Hadoop(单机模式)
  • 原文地址:https://www.cnblogs.com/hellohuman/p/3983025.html
Copyright © 2020-2023  润新知