class websocketUtil { is_open_socket = false; socketStatus = 0 //避免重复连接 0 无连接 1-9连接中 10 已连接 url = ''; data = ''; uuid = ''; timeout = 10000; heartbeatInterval = null; reconnectTimeOut = null; reconnectNum = 0 //重连次数 msgQueue = [] socketTask = null //ws对象 netIsConnected = false netType = 'none' autoFlag = true constructor(url, uuid) { this.is_open_socket = false; //避免重复连接 this.url = url; //地址 this.data = null; this.uuid = getApp().globalData.uuid; //心跳检测 this.timeout = 10000; this.heartbeatInterval = null; //检测服务器端是否还活着 this.reconnectTimeOut = null; //重连之后多久再次重连 // 监听网络状态变化 let that = this; uni.onNetworkStatusChange((res) => { console.log('WebSocket NetStatus', res.isConnected); console.log('WebSocket NetStatus', res.networkType); that.netIsConnected = res.isConnected that.netType = res.networkType that.reconnectNum = 0 if (that.autoFlag) this.reconnect() }); try { uni.getNetworkType({ success: (res) => { console.log('WebSocket getNetworkType', res.networkType); that.netType = res.networkType; that.netIsConnected = true; that.reconnect(); } }); // 有return ,则构造方法返回return的对象,没有,则返回new的对象 // return this.hhh } catch (e) { console.log('连接初始化失败', e); } // try { // return this.connectSocketInit() // } catch (e) { // console.log('catch'); // this.is_open_socket = false // this.reconnect(); // } } //重新连接 reconnect() { // 失败重连频率 const reconnect_time = [3000, 3000, 3000, 3000, 10000, 10000, 10000, 20000, 20000, 50000] // 自身巡检频率 let reconnect_timeout = 30000 //停止发送心跳 // this.heartbeatInterval && clearInterval(this.heartbeatInterval) this.reconnectTimeOut && clearTimeout(this.reconnectTimeOut) if (this.socketStatus < 10) { // 失败重连 if (this.reconnectNum > 50) return; if (this.reconnectNum < reconnect_time.length) { reconnect_timeout = reconnect_time[this.reconnectNum] } else { reconnect_timeout = reconnect_time[reconnect_time.length - 1] } console.log("uniWebsocket 重新连接", this.socketStatus, this.reconnectNum, reconnect_timeout) this.reconnectNum = this.reconnectNum + 1 this.reconnectTimeOut = setTimeout(() => { // 连接创建 this.connectSocketInit(); this.reconnect() }, reconnect_timeout) return; } console.log("uniWebsocket 自身巡检", this.socketStatus, this.reconnectNum, reconnect_timeout) // 自身巡检循环 this.reconnectTimeOut = setTimeout(() => { // 连接创建 this.connectSocketInit(); this.reconnect() }, reconnect_timeout) //如果不是人为关闭的话,进行重连 // if (!this.is_open_socket) { // this.reconnectTimeOut = setTimeout(() => { // this.connectSocketInit(); // }, 3000) // } } generateSeq() { return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function(c) { const r = Math.random() * 16 | 0; const v = c === 'x' ? r : (r & 0x3 | 0x8); return v.toString(16); }); } // 进入这个页面的时候创建websocket连接【整个页面随时使用】 connectSocketInit() { if (!this.netIsConnected || this.netType == 'none') return if (this.socketStatus > 0) return // if(!url) return // if (this.is_open_socket) { // return null; // } this.heartbeatInterval && clearInterval(this.heartbeatInterval) this.socketStatus = 1; uni.onSocketError(function(res) { that.socketStatus = 0; console.log('WebSocket 连接错误!', that.socketStatus, res); }); let that = this; uni.onSocketClose(function(res) { that.socketStatus = 0; that.restart(); console.log('WebSocket 连接关闭!', res); }); uni.onSocketOpen(function(res) { that.socketStatus = 10; console.log('WebSocket 连接打开!', res); }); this.socketTask = uni.connectSocket({ url: that.url, success: () => { that.socketStatus = 2; console.log("正准备建立websocket中..."); return that.socketTask; }, fail: (data) => { that.socketStatus = 0; console.log("websocket 建立失败..."); }, complete: (data) => { that.socketStatus = 3; console.log("websocket 建立完成..."); } }); this.socketTask.onOpen((res) => { console.log("WebSocket连接正常!"); // clearTimeout(this.reconnectTimeOut) // clearInterval(this.heartbeatInterval) that.socketStatus = 10; that.reconnectNum = 0; that.is_open_socket = true; that.start(); console.log("WebSocket连接正常!-start"); // 注:只有连接正常打开中 ,才能正常收到消息 that.socketTask.onMessage((res) => { let resdata = JSON.parse(res.data) //{"seq":"859a0fbd-05c5-4630-a160-e3cf284ad9c9","cmd":"login","response":{"code":200,"codeMsg":"{userId:'1',msg:'欢迎进入~'}","data":null}} console.log(resdata) if (resdata.cmd == "login") { if (resdata.response.codeMsg == "") { getApp().globalData.isLogin = 0; } else { getApp().globalData.isLogin = 1; console.log(resdata.response.codeMsg); getApp().globalData.userId = resdata.response.codeMsg; } uni.$emit('updateGroup', "") //重新加入群组,以便接收消息 } else if (resdata.cmd == "msg") { uni.$emit('messageUpdate', resdata.response.data.msg) } else if (resdata.cmd == "sendMsg") { uni.$emit('messageSend', resdata.response) } else if (resdata.cmd == "heartbeat") { if (resdata.response.code == 1000) { that.toLogin(); } } if (resdata.response.code != 200) { // console.log(res.data) } }); }) // 监听连接失败,这里代码我注释掉的原因是因为如果服务器关闭后,和下面的onclose方法一起发起重连操作,这样会导致重复连接 // uni.onSocketError((res) => { // console.log('WebSocket连接打开失败,请检查!'); // this.is_open_socket = false; // this.reconnect(); // }); // 这里仅是事件监听【如果socket关闭了会执行】 this.socketTask.onClose(() => { console.log("已经被关闭了") that.is_open_socket = false; that.reconnect(); }) } toLogin() { let that = this; that.send({ seq: that.generateSeq(), cmd: "login", data: { "uuid": that.uuid, "appId": 101 } }); } //发送消息 send(value) { value.seq = this.generateSeq(); value = JSON.stringify(value) this.msgQueue.push(value); if (this.socketStatus < 10) { console.log("**********", "连接错误,消息发送失败", value); return; } let that = this; let msg = ''; while (msg = this.msgQueue.shift()) { // 注:只有连接正常打开中 ,才能正常成功发送消息 that.socketTask.send({ data: msg, async success() { console.log('++++++++++', msg) // console.log("消息发送成功"); }, fail(e) { console.log("send-err:", e, msg); //errMsg sendSocketMessage:fail Error: SocketTask.readyState is not OPEN // {"errMsg":"sendSocketMessage:fail WebSocket is not connected"} at common/websocketUtil.js:111 if (e.errMsg.includes("not OPEN") || e.errMsg.includes("fail WebSocket") || e.errMsg .includes("not connected")) { that.close() that.restart(); console.log('is now reconnect'); // console.log(`"${str}" 包含 "${substr}"`); } else { console.log('errMsg', e.errMsg) // console.log(`"${str}" 不包含 "${substr}"`); } } }); } // 注:只有连接正常打开中 ,才能正常成功发送消息 // let that = this; // this.socketTask.send({ // data: JSON.stringify(value), // async success() { // // console.log("消息发送成功"); // }, // fail(e) { // console.log("send-err:", e); // // {"errMsg":"sendSocketMessage:fail WebSocket is not connected"} at common/websocketUtil.js:111 // if (e.errMsg.includes("fail WebSocket") || e.errMsg.includes("not connected")) { // uni.closeSocket(); // that.reconnect(); // console.log('is now reconnect'); // // console.log(`"${str}" 包含 "${substr}"`); // } else { // console.log('errMsg', e.errMsg) // // console.log(`"${str}" 不包含 "${substr}"`); // } // } // }); } getStatus() { return this.socketStatus } //开启心跳检测 start() { let that = this; if (this.heartbeatInterval != null) { clearInterval(this.heartbeatInterval); } console.log("WebSocket连接正常!-start2"); that.send({ seq: that.generateSeq(), cmd: "login", data: { "uuid": that.uuid, "appId": 101 } }); this.heartbeatInterval = setInterval(() => { // console.log("heart",that.timeout); //{"seq":"1565336219141-266129","cmd":"login","data":{"userId":"马远","appId":101}} if (that.socketStatus >= 10) { that.send({ seq: that.generateSeq(), cmd: "heartbeat", data: { "userId": getApp().globalData.userId, "appId": 101 } }); } }, that.timeout) } /** * 重新打开链接 */ restart() { if (this.socketStatus >= 10) { console.log("连接已打开"); return; } console.log("restart") this.autoFlag = true this.reconnect() } /** * 关闭链接 */ close() { console.log("关闭连接") if (this.socketStatus < 10) { console.log("连接未打开"); return; } console.log("清理定时") // heartbeatTimeOut && clearTimeout(heartbeatTimeOut) this.heartbeatInterval && clearInterval(this.heartbeatInterval) this.reconnectTimeOut && clearTimeout(this.reconnectTimeOut) this.autoFlag = false this.socketStatus = 0; this.socketTask.close() console.log("正式关闭") } // stop() { // uni.closeSocket(); // } //外部获取消息 getMessage(callback) { console.log("message", this.socketTask); if (this.socketTask != null) { this.socketTask.onMessage((res) => { return callback(res) }) } } } module.exports = websocketUtil