webSocket 实时通信
http通信是单向的,没有客户端请求就不会有服务器响应,如果服务器有发生变化时,只能通过轮询实现,但是效率低且对服务器压力大,于是有了webSocket
webSocket实现了客户端和服务器的双向平等对话,具有实时性
- 通过new创建一个实例对象,创建连接
onopen连接成功后触发的函数,可在此函数内调用send()方法发送数据,进行通信onmessage收到服务器发送来的数据时触发的函数,在此函数内接受数据onclose连接关闭时触发的函数onerror连接响应意外故障时触发的函数- 可通过
window.onbeforeunload监听窗口关闭事件执行close()方法来关闭webSocket - 通过
readyState属性获取webSocket当前状态
0-连接尚未建立 CONNECTING
1-连接已建立 OPEN
2-连接正在关闭 CLOSING
3-连接已关闭或者连接不能打开 CLOSED
webSocket 心跳包
webSocket超时没有消息时会自动断开连接,心跳包其实就是在未超时之前,每隔一段时间send发送一次,以此来告诉服务器 客户端还需要连接,以此来保持长连接的目的.(这个超时时间是有服务器设置的)
在onopen成功建立起连接后即开启心跳包,需要判断当前是否有websocket实例对象和readyState状态为1连接状态
如果收到了服务器信息,这个时候需要重置心跳,即清除定时器重新执行心跳包,目的是重新计算定时器时间
webSocket 掉线重连
发生意外触发onerror事件,错误会导致连接关闭,很快会触发onclose,在onerror中适合做重连逻辑
data(){
return{
websocket: null, // websocket实例对象
IntervalS: null, // 心跳倒计时对象
socketCount:0, // 重连次数
lockReconnect:false, // 避免重连 重复多次
TimeoutS:null
}
},
mounted () { this.initWebSocket() },
destroyed() {
this.clear()
this.websocket.close() // 关闭websocket
},
// 清除
clear(){
clearInterval(this.IntervaObj)
this.IntervaObj = null
clearTimeout(this.TimeoutS)
this.TimeoutS = null
}
// 创建 websocket 和定义事件
initWebSocket(){
// 判断当前环境是否支持 websocket
if (typeof (WebSocket) == 'undefined') {
this.$notify({
title: '提示',
message: '当前浏览器不支持Websocket通信协议,建议使用谷歌浏览器!',
type: 'warning',
duration: 0
});
} else {
this.websocket = new WebSocket(process.env.VUE_APP_BASE_SOCKET + "/notify")
// 连接成功建立的回调方法
this.websocket.onopen = this.wssOpen
// 接受到消息的回调方法
this.websocket.onmessage = this.wssMessage
// 连接发生错误的回调方法
this.websocket.onerror = this.wssError
// 接受到服务端关闭连接时的回调方法
this.websocket.onclose = this.wssClose
// 监听窗口关闭事件,当窗口关闭时关闭websocket连接,防止连接还没断开就关闭窗口,server端会抛异常
window.onbeforeunload = this.closeWebSocket
}
}
closeWebSocket(){ this.clear() }
wssOpen () {
this.websocket.send("发送数据")
this.start(); // 开启心跳
},
wssMessage(event){
// 处理接受的消息
console.log(event.data)
// 收到服务端消息了可以重置心跳
this.start()
},
wssError () {
//重连3次还是连接不上则关闭websocket
this.socketCount++;
if(this.socketCount <= 2){
this.reconnect(); // 重复连接
console.log("WebSocket连接发生错误" + ' 状态码:' + this.websocket.readyState)
}else{
this.clear()
this.websocket.close()
}
},
wssClose(err){
console.log( "连接关闭" + this.websocket.readyState,err.code)
this.clear()
},
// 开启心跳 30s发送一次
start () {
// 清除时间重新计算s 重置心跳
if(this.IntervalS){
clearInterval(this.IntervalS)
this.IntervalS = null
}
this.IntervalS = setInterval(() => {
// 如果连接正常,每30s发送心跳,否则重连
if (this.websocket && this.websocket.readyState == 1) { // this.websocket.OPEN
this.websocket.send(' ')
} else {
this.reconnect(); // 重复连接
}
}, 30 * 1000)
},
// 重新连接
reconnect () {
// 避免重连 重复多次
if(this.lockReconnect) return
this.lockReconnect = true
// 设置延时器避免请求过多
this.TimeoutS = setTimeout(()=>{
this.initWebSocket();
this.lockReconnect = false;
},10* 1000)
},