首页 > 代码库 > 长轮询实现消息推送

长轮询实现消息推送

一、应用场景
浏览器与服务器之间保持一个长连接(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邮箱收信
 

 

长轮询实现消息推送