WebSocket断开原因、心跳机制防止自动断开连接

1、断开原因

WebSocket断开的原因有很多,最好在WebSocket断开时,将错误打印出来。

ws.onclose = function (e) {
  console.log('websocket 断开: ' + e.code + ' ' + e.reason + ' ' + e.wasClean)
  console.log(e)
}

错误状态码:

WebSocket断开时,会触发CloseEvent, CloseEvent会在连接关闭时发送给使用 WebSockets 的客户端. 它在 WebSocket 对象的 onclose 事件监听器中使用。CloseEvent的code字段表示了WebSocket断开的原因。可以从该字段中分析断开的原因。

CloseEvent有三个字段需要注意, 通过分析这三个字段,一般就可以找到断开原因

  • CloseEvent.code: code是错误码,是整数类型
  • CloseEvent.reason: reason是断开原因,是字符串
  • CloseEvent.wasClean: wasClean表示是否正常断开,是布尔值。一般异常断开时,该值为false
状态码名称描述
0–999保留段, 未使用.
1000CLOSE_NORMAL正常关闭; 无论为何目的而创建, 该链接都已成功完成任务.
1001CLOSE_GOING_AWAY终端离开, 可能因为服务端错误, 也可能因为浏览器正从打开连接的页面跳转离开.
1002CLOSE_PROTOCOL_ERROR由于协议错误而中断连接.
1003CLOSE_UNSUPPORTED由于接收到不允许的数据类型而断开连接 (如仅接收文本数据的终端接收到了二进制数据).
1004保留. 其意义可能会在未来定义.
1005CLOSE_NO_STATUS保留. 表示没有收到预期的状态码.
1006CLOSE_ABNORMAL保留. 用于期望收到状态码时连接非正常关闭 (也就是说, 没有发送关闭帧).
1007Unsupported Data由于收到了格式不符的数据而断开连接 (如文本消息中包含了非 UTF-8 数据).
1008Policy Violation由于收到不符合约定的数据而断开连接. 这是一个通用状态码, 用于不适合使用 1003 和 1009 状态码的场景.
1009CLOSE_TOO_LARGE由于收到过大的数据帧而断开连接.
1010Missing Extension客户端期望服务器商定一个或多个拓展, 但服务器没有处理, 因此客户端断开连接.
1011Internal Error客户端由于遇到没有预料的情况阻止其完成请求, 因此服务端断开连接.
1012Service Restart服务器由于重启而断开连接.
1013Try Again Later服务器由于临时原因断开连接, 如服务器过载因此断开一部分客户端连接.
1014由 WebSocket标准保留以便未来使用.
1015TLS Handshake保留. 表示连接由于无法完成 TLS 握手而关闭 (例如无法验证服务器证书).
1016–1999由 WebSocket标准保留以便未来使用.
2000–2999由 WebSocket拓展保留使用.
3000–3999可以由库或框架使用.? 不应由应用使用. 可以在 IANA 注册, 先到先得.
4000–4999可以由应用使用.

2、加入心跳

var lockReconnect = false;  //避免ws重复连接
var ws = null;          // 判断当前浏览器是否支持WebSocket
var wsUrl = serverConfig.socketUrl;
createWebSocket(wsUrl);   //连接ws

function createWebSocket(url) {
    try{
        if('WebSocket' in window){
            ws = new WebSocket(url);
        }
        initEventHandle();
    }catch(e){
        reconnect(url);
        console.log(e);
    }     
}

function initEventHandle() {
    ws.onclose = function () {
        reconnect(wsUrl);
        console.log("llws连接关闭!"+new Date().toLocaleString());
    };
    ws.onerror = function () {
        reconnect(wsUrl);
        console.log("llws连接错误!");
    };
    ws.onopen = function () {
        heartCheck.reset().start();      //心跳检测重置
        console.log("llws连接成功!"+new Date().toLocaleString());
    };
    ws.onmessage = function (event) {    //如果获取到消息,心跳检测重置
        heartCheck.reset().start();      //拿到任何消息都说明当前连接是正常的
        console.log("llws收到消息啦:" +event.data);
        if(event.data!='pong'){
            let data = JSON.parse(event.data);
        }
    };
}
// 监听窗口关闭事件,当窗口关闭时,主动去关闭websocket连接,防止连接还没断开就关闭窗口,server端会抛异常。
window.onbeforeunload = function() {
    ws.close();
}  

function reconnect(url) {
    if(lockReconnect) return;
    lockReconnect = true;
    setTimeout(function () {     //没连接上会一直重连,设置延迟避免请求过多
        createWebSocket(url);
        lockReconnect = false;
    }, 2000);
}

//心跳检测
var heartCheck = {
    timeout: 1000,        //1分钟发一次心跳
    timeoutObj: null,
    serverTimeoutObj: null,
    reset: function(){
        clearTimeout(this.timeoutObj);
        clearTimeout(this.serverTimeoutObj);
        return this;
    },
    start: function(){
        var self = this;
        this.timeoutObj = setTimeout(function(){
            //这里发送一个心跳,后端收到后,返回一个心跳消息,
            //onmessage拿到返回的心跳就说明连接正常
            ws.send("ping");
            console.log("ping!")
            self.serverTimeoutObj = setTimeout(function(){//如果超过一定时间还没重置,说明后端主动断开了
                ws.close();     //如果onclose会执行reconnect,我们执行ws.close()就行了.如果直接执行reconnect 会触发onclose导致重连两次
            }, self.timeout)
        }, this.timeout)
    }
}
                    
// 收到客户端消息后调用的方法 
    @OnMessage  
    public void onMessage(String message, Session session) {  
        if(message.equals("ping")){
        }else{
        。。。。
        }
   }

系统发现websocket每隔1分钟自动断开连接,搜了很多博客都说设置一下nginx的
proxy_read_timeout
但是这个时间过长会影响服务器性能,采取心跳包的方式每隔1分钟客户端自动发送ping消息给服务端,服务端需要返回pong。即可解决问题。

  • 8
    点赞
  • 70
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值