在项目开发中我们可能经常要使用websocket技术,当连接发生断线后,如果不进行页面刷新将不能正常接收来自服务端的推送消息。为了有效避免这种问题,我们需要在客户端做断线重连处理。当网络或服务出现问题后,客户端会不断检测网络状态,如果服务恢复,客户端则会自动重新连接,并断开本地检测网络的定时器。
一、未做断线检测情况
- 1、项目效果
通过控制台可看到一旦连接关闭,将无法再次收到来自服务器的推送消息。
- 2、未整改前代码
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>排队叫号系统</title>
<link rel="stylesheet" href="/app/admin/component/pear/css/pear.css" />
<link rel="stylesheet" href="/app/admin/admin/css/reset.css" />
</head>
<style>
html{
font-size:14px
}
.pear-container{
background-color: #0d48ff;
//background-color: #2e6fff
}
*{
color:white;
}
.layui-row{
width: 100%;
}
body{
position: absolute;
}
.call-footer {
left: 0;
bottom: 0;
position: fixed;
text-align: center;
padding: 10px;
font-size: 16px;
}
.call-header{
display: flex;
justify-content: space-between;
line-height: 40px;
text-align: center;
border-bottom: 2px dashed #85b8b6;
}
.isemer{
color: red;
}
.call-header>div{
font-size: 30px;
font-family: "楷体","YaHei Consolas Hybrid", Consolas, "微软雅黑", "Meiryo UI", "Malgun Gothic", "Segoe UI", "Trebuchet MS", Helvetica, "Monaco", courier, monospace;
font-weight: 800;
}
#hd-logo>img{
width: 200px;
}
#hd-title {
font-size: 24px;
}
#hd-desc{
font-size: 14px;
}
/*设置显示当前呼叫患者信息*/
#call-place{
height: 28px;
text-align: center;
line-height: 28px;
font-size: 18px;
//color: #6fc9cc;
border-bottom: 2px dashed #85b8b6;
}
.dis-dept{
display: flex;
justify-content:flex-start;
font-size: 28px;
align-items: center;
}
.disp-title{
display: flex;
justify-content: center;
align-items: center;
text-align: center;
padding-right:30px;
border-right: 3px dashed #21f3ff;
margin-top: 20px;
min-width: 200px;
height: 75vh;
}
.disp-title-content{
flex:1;
display: flex;
justify-content: center;
align-items: center;
text-align: center;
font-size: 120px;
border: 10px solid #f8fff7;
border-radius: 50%;
line-height: 100%;
width: 180px;
height: 180px;
}
.disp-content{
flex:1;
display: flex;
justify-content: center;
align-items: center;
height: 75vh;
padding-left: 20px;
}
/*字体大小设置*/
.dispc-text{
font-size: 60px;
overflow: hidden;
}
.layui-layer{
z-index: 9999; /*保证在最上层*/
background-color: rgba(0,0,0,0.5); /*背景半透明*/
}
@keyframes twinkle {
0% {
opacity: 0.9;
}
100% {
opacity: 0.2;
}
}
</style>
<body class="pear-container">
<div class="layui-fluid" >
<div class="row call-header">
<div id="hd-logo"><img src="/app/admin/upload/files/20231128/656599ce1fd4.png" alt=""></div>
<div id="hd-title">1号窗口</div>
<div id="hd-desc">2023-11-28 15:00:00</div>
</div>
<div style="display: none" class="row" id="call-place">
请C003号 王小宝到1号窗口采血
</div>
<div class="layui-row" id="call-display">
<div class="dis-dept">
<div class="disp-title">
<div class="disp-title-content"><?php echo $config['num'];?></div>
</div>
<div class="disp-content" id="disp-con-htm">
<!--<marquee direction="up">-->
<div class="dispc-text">尚未呼叫 <br></div>
<!--</marquee>-->
</div>
</div>
</div>
</div>
<div class="layui-row call-footer" >
请保持安静,耐心等待呼叫!
</div>
<script src="/app/admin/component/layui/layui.js"></script>
<script src="/app/admin/component/pear/pear.js"></script>
<script src="/app/admin/admin/js/common.js"></script>
<script src="/app/queue/component/tools.js"></script>
<script src="/app/queue/component/rpm2h5.js"></script>
<script>
//=========定义显示时间功能结束===================
function clock() {
var time = new Date().toLocaleString();
var htm = '<i class="fa fa-clock-o"></i>' + time;
document.getElementById('hd-desc').innerHTML=htm;
};
setInterval("clock()", 1000);
</script>
<script>
var socket = "";
var token = "room"+readQueryVariable('id','1');
console.log(token);
// var isUpdate = readQueryVariable('isUpdate','0');
// var ws_url = "ws://192.168.40.100:7272?token="+token;
var ws_url = "ws://192.168.40.100:7272?token="+token;
var callMark = "就诊";
layui.use(["table", "form", "common", "popup", "util","layer"], function() {
let table = layui.table;
let form = layui.form;
let $ = layui.$;
let common = layui.common;
let util = layui.util;
let layer = layui.layer;
var loopTimes = 0 ;
// 创建一个新的WebSocket对象
var socket = new WebSocket(ws_url);
// 连接打开时执行的函数
socket.onopen = function(event) {
console.log("已成功连接到服务器");
// 发送一个消息给服务器
//socket.send("你好,服务器!");
};
// 接收到服务器消息时执行的函数
socket.onmessage = function(event) {
loopTimes++;
console.log("从服务器接收到的消息: " + event.data);
};
// 当连接关闭时执行的函数
socket.onclose = function(event)
{
console.log("连接已关闭");
};
// 当出现错误时执行的函数
socket.onerror = function(error) {
console.log("发生错误: " + error);
};
})
</script>
</body>
二、做了断线检测情况
- 1、重连效果
通过控制台观察可发现,在客户端连接成功后,可接收到服务端推送过来的消息,当服务端关闭后,会触发自动重连定时器,当定时器检测到服务连接成功后,会自动完成连接,并可正常接收来自服务端推送的消息。
- 2、支持断线重连完整代码
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>排队叫号系统</title>
<link rel="stylesheet" href="/app/admin/component/pear/css/pear.css" />
<link rel="stylesheet" href="/app/admin/admin/css/reset.css" />
</head>
<style>
html{
font-size:14px
}
.pear-container{
background-color: #0d48ff;
//background-color: #2e6fff
}
*{
color:white;
}
.layui-row{
width: 100%;
}
body{
position: absolute;
}
.call-footer {
left: 0;
bottom: 0;
position: fixed;
text-align: center;
padding: 10px;
font-size: 16px;
}
.call-header{
display: flex;
justify-content: space-between;
line-height: 40px;
text-align: center;
border-bottom: 2px dashed #85b8b6;
}
.isemer{
color: red;
}
.call-header>div{
font-size: 30px;
font-family: "楷体","YaHei Consolas Hybrid", Consolas, "微软雅黑", "Meiryo UI", "Malgun Gothic", "Segoe UI", "Trebuchet MS", Helvetica, "Monaco", courier, monospace;
font-weight: 800;
}
#hd-logo>img{
width: 200px;
}
#hd-title {
font-size: 24px;
}
#hd-desc{
font-size: 14px;
}
/*设置显示当前呼叫患者信息*/
#call-place{
height: 28px;
text-align: center;
line-height: 28px;
font-size: 18px;
//color: #6fc9cc;
border-bottom: 2px dashed #85b8b6;
}
.dis-dept{
display: flex;
justify-content:flex-start;
font-size: 28px;
align-items: center;
}
.disp-title{
display: flex;
justify-content: center;
align-items: center;
text-align: center;
padding-right:30px;
border-right: 3px dashed #21f3ff;
margin-top: 20px;
min-width: 200px;
height: 75vh;
}
.disp-title-content{
flex:1;
display: flex;
justify-content: center;
align-items: center;
text-align: center;
font-size: 120px;
border: 10px solid #f8fff7;
border-radius: 50%;
line-height: 100%;
width: 180px;
height: 180px;
}
.disp-content{
flex:1;
display: flex;
justify-content: center;
align-items: center;
height: 75vh;
padding-left: 20px;
}
/*字体大小设置*/
.dispc-text{
font-size: 60px;
overflow: hidden;
}
.layui-layer{
z-index: 9999; /*保证在最上层*/
background-color: rgba(0,0,0,0.5); /*背景半透明*/
}
@keyframes twinkle {
0% {
opacity: 0.9;
}
100% {
opacity: 0.2;
}
}
</style>
<body class="pear-container">
<div class="layui-fluid" >
<div class="row call-header">
<div id="hd-logo"><img src="/app/admin/upload/files/20231128/656599ce1fd4.png" alt=""></div>
<div id="hd-title">1号窗口</div>
<div id="hd-desc">2023-11-28 15:00:00</div>
</div>
<div style="display: none" class="row" id="call-place">
请C003号 王小宝到1号窗口采血
</div>
<div class="layui-row" id="call-display">
<div class="dis-dept">
<div class="disp-title">
<div class="disp-title-content"><?php echo $config['num'];?></div>
</div>
<div class="disp-content" id="disp-con-htm">
<!--<marquee direction="up">-->
<div class="dispc-text">尚未呼叫 <br></div>
<!--</marquee>-->
</div>
</div>
</div>
</div>
<div class="layui-row call-footer" >
请保持安静,耐心等待呼叫!
</div>
<script src="/app/admin/component/layui/layui.js"></script>
<script src="/app/admin/component/pear/pear.js"></script>
<script src="/app/admin/admin/js/common.js"></script>
<script src="/app/queue/component/tools.js"></script>
<script src="/app/queue/component/rpm2h5.js"></script>
<script>
//=========定义显示时间功能结束===================
function clock() {
var time = new Date().toLocaleString();
var htm = '<i class="fa fa-clock-o"></i>' + time;
document.getElementById('hd-desc').innerHTML=htm;
};
setInterval("clock()", 1000);
</script>
<script>
var socket = "";
var token = "room"+readQueryVariable('id','1');
console.log(token);
// var isUpdate = readQueryVariable('isUpdate','0');
// var ws_url = "ws://192.168.40.100:7272?token="+token;
var ws_url = "ws://192.168.40.100:7272?token="+token;
var callMark = "就诊";
layui.use(["table", "form", "common", "popup", "util","layer"], function() {
let table = layui.table;
let form = layui.form;
let $ = layui.$;
let common = layui.common;
let util = layui.util;
let layer = layui.layer;
var loopTimes = 0 ;
function connectWS(){
try{
socket = new WebSocket(ws_url);
// 连接打开时执行的函数
socket.onopen = function(event) {
console.log("已成功连接到服务器");
// 发送一个消息给服务器
socket.send(token);
};
// 接收到服务器消息时执行的函数
socket.onmessage = function(event) {
console.log("从服务器接收到的消息: " + event.data);
};
// 当连接关闭时执行的函数
socket.onclose = function(event)
{
console.log("连接已关闭");
reConnect();
};
// 当出现错误时执行的函数
socket.onerror = function(error) {
console.log("发生错误: " + error);
};
}catch(ex){
console.log(ex.message);
}
};
// 调用链接socket函数
connectWS();
// 断线重新连接websocket
function reConnect()
{
let timeId = setInterval(function(){
console.log("正在努力重连。。。");
if(socket.readyState===WebSocket.CLOSED)
{
connectWS();
// 重新连接成功后清除定时器
clearInterval(timeId);
}
},3000);
}
})
</script>
</body>
希望各位小伙伴们都能学会了!