js websocket自动重连机制(心跳后续)

ApiPost-宣博文 前端 2021-04-19
window.webSocket = {};
var heartCheck = {
    lockReconnect: false, //避免ws重复连接
    maxReconnectionDelay: 30 * AP.MINUTE, //最大重连时间
    minReconnectionDelay: 10 * AP.SECOND, //最小重连时间
    reconnectionDelayGrowFactor: 1.5, //自动重连失败后重连时间倍数增长
    connectionTimeout: 10 * AP.SECOND,//重连时间
    pongTime: 30 * AP.SECOND, //30秒接收心跳
    pingTime: (30 * AP.SECOND / 10) * 8,//30秒向服务器发送心跳
    timeoutObj: null,//Ping定时器
    serverTimeoutObj: null,//Pong定时器
    reset: function () {
        // clearTimeout(this.timeoutObj);
        clearTimeout(this.serverTimeoutObj);
        return this;
    },
    PingStart: function () {
        var self = this;
        this.timeoutObj = setTimeout(function () {
            //这里发送一个心跳,后端收到后,返回一个心跳消息,
            //onmessage拿到返回的心跳就说明连接正常
            if (WEB_SOCKET != null && WEB_SOCKET.readyState == WebSocket.OPEN) {
                WEB_SOCKET.send("PING")
                self.PingStart();
            }
        }, this.pingTime) //10秒发送一次心跳
    },
    PongStart: function () {
        var self = this;
        self.serverTimeoutObj = setTimeout(function () { //如果超过一定时间还没重置,说明后端主动断开了
            if (WEB_SOCKET != null) {
                //console.log("服务器30秒没有响应,关闭连接")
                WEB_SOCKET.close();
            }
        }, self.pongTime)
    }
}
//自动重连
webSocket.reconnect = function () {
	//避免ws重复连接
    if (heartCheck.lockReconnect) return;

    heartCheck.lockReconnect = true;
    setTimeout(function () { //没连接上会一直重连,设置延迟避免请求过多
        webSocket.socketInit(true);
        heartCheck.lockReconnect = false;
    }, heartCheck.connectionTimeout);

    if (heartCheck.connectionTimeout >= heartCheck.minReconnectionDelay && heartCheck.connectionTimeout < heartCheck.maxReconnectionDelay) {
        heartCheck.connectionTimeout = heartCheck.connectionTimeout * heartCheck.reconnectionDelayGrowFactor
    } else {
        heartCheck.connectionTimeout = heartCheck.minReconnectionDelay;
    }
}
//实际应用
//参数:reconnection  判断是不是自动重连  可以在后期对业务进行不同的处理 例如正常连接走一段代码,断线重连走另一段
webSocket.socketInit = function (reconnection = false) {
    return new Promise((resolve, reject) => {
        if ("这里可以判断用户网络状态 或者 用户登录情况") {
            if (WEB_SOCKET == null) {
                    WEB_SOCKET = new WebSocket("ws://88.gaoqiaoxue.com/v5/apipost.io?userToken=" + AP.USER.userIndendify);
                    WEB_SOCKET.onopen = function (evt) {
                        //console.log("连接成功,发送ping");
                        WEB_SOCKET.send("PING")
                        heartCheck.PingStart();
                        heartCheck.reset().PongStart(); //打开心跳检测
                        //console.log("Connection open ...", evt, WEB_SOCKET);
                        resolve(true)
                    };
                    WEB_SOCKET.onerror = function (err) {
                        //console.log(err);
                        if (WEB_SOCKET != null) {
                            //console.log("异常,关闭连接", err);
                            WEB_SOCKET.close();
                        } else {
                            webSocket.reconnect(); //打开自动重连
                        }
                        reject(err)
                    }
                    WEB_SOCKET.onmessage = function (evt) {
                        if (WEB_SOCKET != null) {
                            heartCheck.reset().PongStart(); //拿到任何消息都说明当前连接是正常的 心跳检测重置
                        }
                    };

                    WEB_SOCKET.onclose = function (evt) {
                        //console.log("Connection closed.");
                        webSocket.reconnect(); //打开自动重连
                        resolve(true)
                    };
                }
            } else {
                switch (WEB_SOCKET.readyState) {
                    case WebSocket.CONNECTING: //表示正在连接。
                        //console.log("正在连接");
                        resolve(true)
                        break;
                    case WebSocket.OPEN: //表示连接成功,可以通信了。
                        //console.log("已经连接");
                        resolve(true)
                        break;
                    case WebSocket.CLOSING: //表示连接正在关闭。
                        //console.log("正在关闭,1秒后再次尝试连接");
                        setTimeout(() => {
                            webSocket.socketInit();
                        }, 1000);
                        resolve(true)
                        break;
                    case WebSocket.CLOSED: //表示连接已经关闭,或者打开连接失败
                        //console.log("已经关闭,再次连接");
                        WEB_SOCKET = null;
                        webSocket.socketInit(true);
                        resolve(true)
                        break;
                    default:
                        // this never happens
                        break;
                }
        } else {
            webSocket.reconnect(); //重新连接
            reject(false)
        }
    }).catch((e) => {
        webSocket.reconnect(); //重新连接
    })
}

代码已经写的很详细了,谢谢观看,如果您还有其他相关问题,欢迎留言

Apipost 私有化火热进行中

评论