利用nginx代理websocket的时候,发现客户端和服务器握手成功后,如果在60s时间内没有数据交互,连接就会自动断开,如下图:
为了保持长连接,可以采取来两种方式.
1.nginx.conf 文件里location 中的proxy_read_timeout 默认60s断开,可以把他设置大一点,你可以设置成自己需要的时间,我这里设置的是十分钟(600s).
nginx配置如下:
server { listen 80; server_name carrefourzone.senguo.cc; #error_page 502 /static/502.html; location /static/ { root /home/chenming/Carrefour/carrefour.senguo.cc/source; expires 7d; } location / { proxy_pass_header Server; proxy_set_header Host $http_host; proxy_redirect off; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Scheme $scheme; proxy_pass http://127.0.0.1:9887; proxy_http_version 1.1; proxy_set_header Upgrade "websocket"; proxy_set_header Connection "Upgrade"; proxy_read_timeout 600s; } }
# 重启nginx服务
sudo nginx -s reload
按照上述方法设置好后,我们可以发现,如果在10分钟之内没有数据交互的话,websocket连接就会自动断开,所以这种方式还是有点问题,如果我页面停留时间超过十分钟而且又没有数据交互的话,连接还是会断开的,所以需要同时结合第二种方法.
2.在nginx延长超时时间的基础上,前端在超时时间内发心跳包,刷新再读时间,前端具体实现见如下代码(此处代码包含了前端整个websocket的实现过程,其中红色重点标注了发心跳包的内容):
// websocket连接 var websocket_connected_count = 0; var onclose_connected_count = 0; function newWebSocket(){ var websocket = null; // 判断当前环境是否支持websocket if(window.WebSocket){ if(!websocket){ var ws_url ="wss://"+domain+"/updatewebsocket"; websocket = new WebSocket(ws_url); } }else{ Tip("not support websocket"); } // 连接成功建立的回调方法 websocket.onopen = function(e){ heartCheck.reset().start(); // 成功建立连接后,重置心跳检测 Tip("connected successfully") } // 连接发生错误,连接错误时会继续尝试发起连接(尝试5次) websocket.onerror = function() { console.log("onerror连接发生错误") websocket_connected_count++; if(websocket_connected_count <= 5){ newWebSocket() } } // 接受到消息的回调方法 websocket.onmessage = function(e){ console.log("接受到消息了") heartCheck.reset().start(); // 如果获取到消息,说明连接是正常的,重置心跳检测 var message = e.data; if(message){ //执行接收到消息的操作,一般是刷新UI } } // 接受到服务端关闭连接时的回调方法 websocket.onclose = function(){ Tip("onclose断开连接"); } // 监听窗口事件,当窗口关闭时,主动断开websocket连接,防止连接没断开就关闭窗口,server端报错 window.onbeforeunload = function(){ websocket.close(); } // 心跳检测, 每隔一段时间检测连接状态,如果处于连接中,就向server端主动发送消息,来重置server端与客户端的最大连接时间,如果已经断开了,发起重连。 var heartCheck = { timeout: 55000, // 9分钟发一次心跳,比server端设置的连接时间稍微小一点,在接近断开的情况下以通信的方式去重置连接时间。 serverTimeoutObj: null, reset: function(){ clearTimeout(this.timeoutObj); clearTimeout(this.serverTimeoutObj); return this; }, start: function(){ var self = this; this.serverTimeoutObj = setInterval(function(){ if(websocket.readyState == 1){ console.log("连接状态,发送消息保持连接"); websocket.send("ping"); heartCheck.reset().start(); // 如果获取到消息,说明连接是正常的,重置心跳检测 }else{ console.log("断开状态,尝试重连"); newWebSocket(); } }, this.timeout) } } }
上述过程就是保持长连接的过程,前端部分也包含了大部分websocket初始化的内容.
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 记一次.NET内存居高不下排查解决与启示
· 探究高空视频全景AR技术的实现原理
· 理解Rust引用及其生命周期标识(上)
· 浏览器原生「磁吸」效果!Anchor Positioning 锚点定位神器解析
· 没有源码,如何修改代码逻辑?
· 分享4款.NET开源、免费、实用的商城系统
· 全程不用写代码,我用AI程序员写了一个飞机大战
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了
· 上周热点回顾(2.24-3.2)