在业务中需要使用webSocket定时给后台上传位置,防止以后忘记,在这里进行记录,直接在代码中写入笔记;
<template>
<div id='main' ref='main'>
<van-button @click="OnLocation">开启</van-button>
<van-button @click="OnClose">关闭socket</van-button>
</div>
</template>
<script>
export default {
data() {
return {
lc: {}, // 经纬度
ws: null, // webSocket实例
webSocketState: false, // webSocket的连接状态
heartBeat: { // 心跳连接的时间设置
time: 5 * 1000, // 心跳时间间隔
timeout: 3 * 1000, // timeout:心跳超时间隔(!要少于心跳间隔)
reconnect: 10 * 1000 // 断线重连时间
},
reconnectTimer: null, // 断线重连时间器
}
},
methods: {
OnClose() {
this.ws.close(); //关闭webSocket连接
this.webSocketState = false; //关闭状态
this.heartBeat.time = null; //停止心跳
if (this.reconnectTimer) { //关闭重连
clearInterval(this.reconnectTimer);
}
},
//开启按钮
OnLocation() {
this.heartBeat.time = 5 * 1000; //因为关闭时会置空,所以在这重新初始化一下
this.wlhy.getLocation(); //这里是我自己业务中取经纬度的,
this.connectWebSocket(); //建立连接
},
//socket链接
connectWebSocket() {
let url = `wss://ws://baidu.com/msg/${this.userInfo.userId}`;
//这里连接地址根据自己的业务设置,注意:如果连接本地进行调试的时候,要用'ws',如:“ws://192.168.2.15:8080/msg”
this.ws = new WebSocket(url);
this.init(); //初始化
},
init() {
this.ws.addEventListener('open', () => {
// eslint-disable-next-line spaced-comment
this.webSocketState = true; //socket状态设置为连接,做为后面的断线重连的拦截器
// eslint-disable-next-line no-unused-expressions
console.log('开启');
this.heartBeat && this.heartBeat.time ? this.startHeartBeat(this.heartBeat.time) : ''; // 是否启动心跳机制
});
this.ws.addEventListener('message', (e) => {
this.webSocketState = true;
console.log(JSON.parse(e.data),'信息')
});
this.ws.addEventListener('close', (e) => {
this.webSocketState = false; // socket状态设置为断线
console.log('断开了连接');
});
this.ws.addEventListener('error', (e) => {
this.webSocketState = false; // socket状态设置为断线
this.reconnectWebSocket(); // 重连
console.log('连接发生了错误');
});
},
// 心跳 time:心跳时间间隔
startHeartBeat(time) {
setTimeout(() => {
//这里设置这是你要发送的内容
let data = {};
data.lon = this.lc.longitude; //已省略获取地址步骤
data.lat = this.lc.latitude;
this.ws.send(JSON.stringify(data)) //发送数据
this.waitingServer();
}, time);
},
// 延时等待服务端响应,通过webSocketState判断是否连线成功
waitingServer() {
this.webSocketState = false;
setTimeout(() => {
if (this.webSocketState) {
this.startHeartBeat(this.heartBeat.time);
return;
}
console.log('心跳无响应,已断线');
try {
this.ws.close();
} catch (e) {
console.log('连接已关闭,无需关闭');
}
this.reconnectWebSocket(); //非主动关闭导致,触发重连
}, this.heartBeat.timeout);
},
// 重连操作
reconnectWebSocket() {
this.reconnectTimer = setTimeout(() => {
this.reconnectWs();
}, this.heartBeat.reconnect);
},
reconnectWs() {
if(!this.heartBeat.time) return //如果主动关闭,则防止重连
if (!this.ws) {
// 第一次执行,初始化
this.connectWebSocket();
}
if (this.ws && this.reconnectTimer) {
// 防止多个websocket同时执行
clearTimeout(this.reconnectTimer);
this.ws.reconnectTimer = null;
this.connectWebSocket();
}
},
},
}
</script>
注意:我在开发过程中发现,当我主动关闭连接后,在重连时间内会自动重新开启连接,这是因为websocket连接关闭会又走一次重连机制,所以 如果你是使用的定时器,可以直接清除定时器,或者定义一个变量控制是组件销毁关闭的websocket还是心跳监测重连时关闭的websocket,如果是像我一样,可以判断this.heartBeat.time,关闭后置空,判断return就可以了;
下面是直接用定时器做的心跳(在这里没有主动关闭的功能)
<script>
export default {
name: "clockIn",
data(){
return {
lc: {}, //经纬度(获取过程省略)
interval: null, //定时器
socket: null, //socket
}
},
mounted() {},
methods: {
initSocket() {
/**主流浏览器都支持 webSocket 通信,但建议还是要判断*/
if ("WebSocket" in window) {
if (this.socket) {
this.socket.close();
}
/**创建 web socket 实例
* 如果连接失败,浏览器控制台报错,连接失败
* 前缀 ws:// 必须正确,weChatInteract 是应用名称,webSocket/shake.action 是后台访问路径
* */
let url = `ws://192.168.2.15:8080/msg`;
this.socket = new WebSocket(url);
let _this = this;
/**onopen:服务器连接成功后,自动触发*/
this.socket.onopen = function() {
this.interval = setInterval(function() {
/** Web Socket 已连接上,使用 send() 方法发送数据*/
let data = {};
data.lon = lc.longitude;
data.lat = lc.latitude;
console.log(data)
_this.socket.send(JSON.stringify(data))
console.log("服务器连接成功,并发送数据到后台...");
},30000)
}
/**服务器发送数据后,自动触发此方法,客户端进行获取数据,使用 evt.data 获取数据*/
this.socket.onmessage = function(msg) {
if (msg.data && msg.data != 'messageCenter login success') {
// let message = JSON.parse(msg.data);
console.log(message,'=> 接收到服务器数据')
}
}
/**客户端与服务器数据传输错误时触发*/
this.socket.onerror = function (evt) {
console.log("客户端 与 服务器 数据传输错误...");
};
/**web Socket 连接关闭时触发*/
this.socket.onclose = function(e) {
console.log("web scoket 连接关闭...");
if (this.interval) {
clearInterval(this.interval);
}
setTimeout(function() {
_this.initSocket();
},5000)
}
} else {
console.log("浏览器不支持 WebSocket!");
}
},
},
</script>
参考链接: