如何解决webSocket自动断开连接
dearweb 发布:2022-07-01 23:51:20阅读:一般情况下,前端页面连接WebSocket服务的时候都是通过Nginx等负载均衡,然后由Nginx去代理连接后端的socket服务。Nginx的配置类似如下:
map $http_upgrade $connection_upgrade { default upgrade; '' close; } location / { proxy_pass https://socket; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_http_version 1.1; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection $connection_upgrade; }
如果建立连接之后不做一些措施,那么可能会有各种各样的原因会导致socket断开,最好在socket断开时将错误打印出来。
ws.onclose = function (ev) { console.log('socket 断开: ' + ev.code + ' ' + ev.reason + ' ' + ev.wasClean) }
socket断开时,会触发CloseEvent, CloseEvent会在连接关闭时发送给使用 WebSocket 的客户端,它在 WebSocket 对象的 onclose 事件监听器中使用。 CloseEvent有三个字段需要注意, 通过分析这三个字段,一般就可以找到断开原因:
CloseEvent.code: code是错误码,是整数类型
CloseEvent.reason: reason是断开原因,是字符串
CloseEvent.wasClean: wasClean表示是否正常断开,是布尔值。一般异常断开时,该值为false
为了保证socket稳定,不断开,最好也是最简单的办法是添加一些逻辑,一直保持socket处在连接的状态。常见的做法就是间隔发ping消息给服务端,服务端接收到这个消息之后返回pong消息,以此来保持心跳,以防sock断开。我们常见的ping消息和pong消息实际上是发送了一个文本消息,这个消息的内容是ping或者pong,甚至是heatbeat等等,但是从socket协议来说是有设计ping消息和pong消息的。在socket的数据帧中,有一个opcode,它表明了socket的数据帧是什么类型的:
%x0:表示一个延续帧。当Opcode为0时,表示本次数据传输采用了数据分片,当前收到的数据帧为其中一个数据分片。
%x1:表示这是一个文本帧(frame)
%x2:表示这是一个二进制帧(frame)
%x3-7:保留的操作代码,用于后续定义的非控制帧。
%x8:表示连接断开。
%x9:表示这是一个ping操作。
%xA:表示这是一个pong操作。
%xB-F:保留的操作代码,用于后续定义的控制帧。
规范的心跳应该是在opcode里定义type:ping(9)才对,消息的内容是null,什么都没有,这才是最轻量级最规范的websocket心跳机制。一般情况下,使用发文本消息的方式也是没啥问题的,无非就是多消耗了一点流量和带宽,调试起来也容易一些,有可能心跳消息本身就会带一些业务数据。
js代码如下:
var lockReconnect = false; var ws = null; var wsUrl = 'wss://127.0.0.1/socket' createWebSocket(wsUrl); 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 (ev) { reconnect(wsUrl); console.log('socket 断开: ' + ev.code + ' ' + ev.reason + ' ' + ev.wasClean) }; ws.onerror = function (ev) { reconnect(wsUrl); console.log("llws连接错误!"); }; ws.onopen = function () { heartCheck.reset().start(); console.log("llws连接成功!"+new Date().toLocaleString()); }; ws.onmessage = function (message) { heartCheck.reset().start(); //拿到任何消息都说明当前连接是正常的 console.log("llws收到消息啦:" +message.data); if(message.data!='pong'){ var msg = JSON.parse(message.data); } }; }
当窗口关闭时,主动去关闭websocket连接
window.onbeforeunload = function() { ws.close(); } function reconnect(url) { if(lockReconnect) return; lockReconnect = true; setTimeout(function () { //没连接上会一直重连,设置延迟避免请求过多 createWebSocket(url); lockReconnect = false; }, 2000); } var heartCheck = { timeout: 3000, timeoutObj: null, serverTimeoutObj: null, reset: function(){ clearTimeout(this.timeoutObj); clearTimeout(this.serverTimeoutObj); return this; }, start: function(){ var self = this; this.timeoutObj = setTimeout(function(){ ws.send("ping"); console.log("ping!") self.serverTimeoutObj = setTimeout(function(){ //如果超过一定时间还没重置,说明后端主动断开了 ws.close(); }, self.timeout) }, this.timeout) } }
服务端Java代码:
@OnMessage public void onMessage(String message, Session session) { if(message.equals("ping")){ }else{ } }
小礼物走一波,支持作者
赏还没有人赞赏,支持一波吧