封装类和心跳机制
1
class WebSocketClass {/*** @description: 初始化实例属性,保存参数* @param {String} url ws的接口* @param {Function} msgCallback 服务器信息的回调传数据给函数* @param {String} name 可选值 用于区分ws,用于debugger*/constructor(url, msgCallback, name = 'default') {this.url = url;this.msgCallback = msgCallback;this.name = name;this.ws = null; // websocket对象this.status = null; // websocket是否关闭}/*** @description: 初始化 连接websocket或重连webSocket时调用* @param {*} 可选值 要传的数据*/connect(data) {// 新建 WebSocket 实例this.ws = new WebSocket(this.url);this.ws.onopen = e => {// 连接ws成功回调this.status = 'open';console.log(`${this.name}连接成功`, e)// this.heartCheck();if (data !== undefined) {// 有要传的数据,就发给后端return this.ws.send(data);}}// 监听服务器端返回的信息this.ws.onmessage = e => {// 把数据传给回调函数,并执行回调// if (e.data === 'pong') {// this.pingPong = 'pong'; // 服务器端返回pong,修改pingPong的状态// }return this.msgCallback(e.data);}// ws关闭回调this.ws.onclose = e => {this.closeHandle(e); // 判断是否关闭}// ws出错回调this.onerror = e => {this.closeHandle(e); // 判断是否关闭}}// heartCheck() {// // 心跳机制的时间可以自己与后端约定// this.pingPong = 'ping'; // ws的心跳机制状态值// this.pingInterval = setInterval(() => {// if (this.ws.readyState === 1) {// // 检查ws为链接状态 才可发送// this.ws.send('ping'); // 客户端发送ping// }// }, 10000)// this.pongInterval = setInterval(() => {// this.pingPong = false;// if (this.pingPong === 'ping') {// this.closeHandle('pingPong没有改变为pong'); // 没有返回pong 重启webSocket// }// // 重置为ping 若下一次 ping 发送失败 或者pong返回失败(pingPong不会改成pong),// //将重启// console.log('返回pong')// this.pingPong = 'ping'// }, 20000)// }// 发送信息给服务器sendHandle(data) {console.log(`${this.name}发送消息给服务器:`, data)return this.ws.send(data);}closeHandle(e = 'err') {// 因为webSocket并不稳定,规定只能手动关闭(调closeMyself方法),否则就重连if (this.status !== 'close') {console.log(`${this.name}断开,重连websocket`, e)// if (this.pingInterval !== undefined && this.pongInterval !== undefined) {// // 清除定时器// clearInterval(this.pingInterval);// clearInterval(this.pongInterval);// }this.connect(); // 重连} else {console.log(`${this.name}websocket手动关闭`)}}// 手动关闭WebSocketcloseMyself() {console.log(`关闭${this.name}`)this.status = 'close';return this.ws.close();}}function someFn(data) {console.log('接收服务器消息的回调:', data);}// const wsValue = new WebSocketClass('ws://121.40.165.18:8800', someFn, 'wsName');// 这个链接一天只能发送消息50次const wsValue = new WebSocketClass('wss://echo.websocket.org', someFn, 'wsName');// 阮一峰老师教程链接wsValue.connect('立即与服务器通信'); // 连接服务器// setTimeout(() => {// wsValue.sendHandle('传消息给服务器')// }, 1000);// setTimeout(() => {// wsValue.closeMyself(); // 关闭ws// }, 10000)
参考:https://segmentfault.com/a/1190000016797885?utm_source=sf-similar-article
2
var lockReconnect = false; //避免ws重复连接var ws = null; // 判断当前浏览器是否支持WebSocketvar wsUrl = serverConfig.socketUrl;createWebSocket(wsUrl); //连接wsfunction 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)}}// 收到客户端消息后调用的方法@OnMessagepublic void onMessage(String message, Session session) {if(message.equals("ping")){}else{。。。。}}
