详解JS WebSocket断开原因和心跳机制


Posted in Javascript onMay 07, 2021

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   保留段, 未使用.
1000 CLOSE_NORMAL 正常关闭; 无论为何目的而创建, 该链接都已成功完成任务.
1001 CLOSE_GOING_AWAY 终端离开, 可能因为服务端错误, 也可能因为浏览器正从打开连接的页面跳转离开.
1002 CLOSE_PROTOCOL_ERROR 由于协议错误而中断连接.
1003 CLOSE_UNSUPPORTED 由于接收到不允许的数据类型而断开连接 (如仅接收文本数据的终端接收到了二进制数据).
1004   保留. 其意义可能会在未来定义.
1005 CLOSE_NO_STATUS 保留. 表示没有收到预期的状态码.
1006 CLOSE_ABNORMAL 保留. 用于期望收到状态码时连接非正常关闭 (也就是说, 没有发送关闭帧).
1007 Unsupported Data 由于收到了格式不符的数据而断开连接 (如文本消息中包含了非 UTF-8 数据).
1008 Policy Violation 由于收到不符合约定的数据而断开连接. 这是一个通用状态码, 用于不适合使用 1003 和 1009 状态码的场景.
1009 CLOSE_TOO_LARGE 由于收到过大的数据帧而断开连接.
1010 Missing Extension 客户端期望服务器商定一个或多个拓展, 但服务器没有处理, 因此客户端断开连接.
1011 Internal Error 客户端由于遇到没有预料的情况阻止其完成请求, 因此服务端断开连接.
1012 Service Restart 服务器由于重启而断开连接.
1013 Try Again Later 服务器由于临时原因断开连接, 如服务器过载因此断开一部分客户端连接.
1014   由 WebSocket标准保留以便未来使用.
1015 TLS 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。即可解决问题。

以上就是详解JS WebSocket断开原因和心跳机制的详细内容,更多关于JS WebSocket断开原因和心跳机制的资料请关注三水点靠木其它相关文章!

Javascript 相关文章推荐
JavaScript 基础篇(一)
Mar 30 Javascript
Javascript中的return作用及javascript return关键字用法详解
Nov 05 Javascript
js实现下拉列表选中某个值的方法(3种方法)
Dec 17 Javascript
JS代码实现table数据分页效果
May 26 Javascript
JS全局变量和局部变量最新解析
Jun 24 Javascript
jQuery Easyui使用(一)之可折叠面板的布局手风琴菜单
Aug 17 Javascript
为jQuery-easyui的tab组件添加右键菜单功能的简单实例
Oct 10 Javascript
详解在Vue中通过自定义指令获取dom元素
Mar 04 Javascript
详解基于vue的移动web app页面缓存解决方案
Aug 03 Javascript
JSON创建键值对(key是中文或者数字)方式详解
Aug 24 Javascript
JS实现为动态创建的元素添加事件操作示例
Mar 17 Javascript
Angular7中创建组件/自定义指令/管道的方法实例详解
Apr 02 Javascript
如何用threejs实现实时多边形折射
详解JS ES6编码规范
May 07 #Javascript
html5中sharedWorker实现多页面通信的示例代码
May 07 #Javascript
详解如何使用Node.js实现热重载页面
May 06 #Javascript
关于Vue Router的10条高级技巧总结
May 06 #Vue.js
在JavaScript中如何使用宏详解
May 06 #Javascript
如何用JS实现简单的数据监听
May 06 #Javascript
You might like
国产动画《伍六七》原声大碟大卖,啊哈娱乐引领音乐赋能IP的新尝试
2020/03/08 国漫
PHP 危险函数解释 分析
2009/04/22 PHP
elgg 获取文件图标地址的方法
2010/03/20 PHP
PHP中in_array的隐式转换的解决方法
2018/03/06 PHP
PHP实现单文件、多个单文件、多文件上传函数的封装示例
2019/09/02 PHP
最新的10款jQuery内容滑块插件分享
2011/09/18 Javascript
javascript页面加载完执行事件代码
2014/02/11 Javascript
from表单多个按钮提交用onclick跳转不同action
2014/04/24 Javascript
JS+CSS实现弹出全屏灰黑色透明遮罩效果的方法
2014/12/20 Javascript
一个简单的JavaScript Map实例(分享)
2016/08/03 Javascript
js提示框替代系统alert,自动关闭alert对话框的实现方法
2016/11/07 Javascript
JavaScript设计模式之策略模式详解
2017/06/09 Javascript
随机生成10个不重复的0-100的数字(实例讲解)
2017/08/16 Javascript
vue3.0 CLI - 1 - npm 安装与初始化的入门教程
2018/09/14 Javascript
微信小程序实现两边小中间大的轮播效果的示例代码
2018/12/07 Javascript
vue拖拽组件 vuedraggable API options实现盒子之间相互拖拽排序
2019/07/08 Javascript
JavaScript实现PC端四格密码输入框功能
2020/02/19 Javascript
CentOS 8.2服务器上安装最新版Node.js的方法
2020/12/16 Javascript
[46:04]Liquid vs VP Supermajor决赛 BO 第四场 6.10
2018/07/05 DOTA
讲解Python的Scrapy爬虫框架使用代理进行采集的方法
2016/02/18 Python
Python实现的生产者、消费者问题完整实例
2018/05/30 Python
Pycharm新建模板默认添加个人信息的实例
2019/07/15 Python
Django框架组成结构、基本概念与文件功能分析
2019/07/30 Python
python实现LRU热点缓存及原理
2019/10/29 Python
python基于TCP实现的文件下载器功能案例
2019/12/10 Python
Python单元测试模块doctest的具体使用
2020/02/10 Python
Pyecharts 动态地图 geo()和map()的安装与用法详解
2020/03/25 Python
PyQt5的QWebEngineView使用示例
2020/10/20 Python
python 指定源路径来解决import问题的操作
2021/03/04 Python
德国电子产品购物网站:TechInTheBasket德国
2018/12/07 全球购物
do you have any Best Practice for testing
2016/06/04 面试题
小区文明倡议书
2014/05/16 职场文书
债务纠纷代理词
2015/05/25 职场文书
色戒观后感
2015/06/12 职场文书
2016形势与政策学习心得体会
2016/01/12 职场文书
2016年幼儿园教研活动总结
2016/04/05 职场文书