功能描述:websocket是一种在单个TCP连接上进行全双工通信的协议,它能够在客户端和服务器之间建立持久的连接,使得实时通讯成为可能。在前端开发中,WebSocket通常用于实现实时消息推送、实时数据更新等功能,为用户提供更流畅、即时的体验
本文将介绍如何在前端项目中利用WebSocket实现与后端的实时通讯,并结合具体的代码示例进行讲解。
实现单例模式的SocketService类
在本文中,我们将使用一个名为SocketService
的类来封装WebSocket的相关操作,并通过单例模式确保在整个应用程序中只有一个SocketService
实例存在。这样可以避免多次实例化和重复连接服务器的问题,同时方便在应用程序的不同模块中共享同一个SocketService
实例,实现统一的数据传输和处理逻辑。
创建utils文件夹--->websocket.js文件
import { LoginWebSocketApi } from "@/request/api";
export default class SocketService {
// 用于实现单例模式的写法
// 可以确保在整个应用程序中只有一个SocketService实例存在,避免了多次实例化和重复连接服务器的问题。通过单例模式,可以方便地在应用程序的不同模块中共享同一个SocketService实例,实现统一的数据传输和处理逻辑。
static instance = null;
static get Instance() {
if (!this.instance) {
this.instance = new SocketService()
}
return this.instance
}
ws = null
// 标识是否连接成功
connected = false
// 重试的次数
sendRetryCount = 0
// 重连的次数
connectRetryCount = 0
// 存储回调函数
// callBackMapping = {}
heartbeatInterval = null;
// 连接服务器的方法
connect(vue) {
// 连接服务器
if (!window.WebSocket) {
return console.log("浏览器不支持webSocket")
}
if (!localStorage.getItem("token")) {
console.log('没有token,不连接WebSocket');
return;
}
this.ws = new WebSocket("wss://你的地址");
// 连接成功的事件
this.ws.onopen = () => {
console.log("连接成功");
this.connected = true;
this.connectRetryCount = 0;
clearTimeout(this.heartbeatInterval);
this.start();
}
// 连接失败的事件
this.ws.onclose = () => {
console.log("连接失败")
this.connected = false;
if (this.connectRetryCount <= 100) {
this.connectRetryCount++
}
setTimeout(() => {
this.connect(vue)
}, this.connectRetryCount * 500)
}
// 收到数据的事件
this.ws.onmessage = (res) => {
// console.log("获取信息", res.data)
try {
console.log('接收消息', res.data);
let data_arr = JSON.parse(res.data);
let type = data_arr.type;
// 处理不同类型的消息
switch (type) {
case 'login':
this.login_websocket(data_arr.client_id);
break;
case 'charge_normal_end':
vue.$bus.$emit('charge_normal_end', data_arr);
break;
case 'shots_count_change':
vue.$bus.$emit('shots_count_change', data_arr);
break;
default:
break;
}
} catch (e) {
console.log('e', e);
}
}
}
login_websocket(client_id) {
LoginWebSocketApi({
client_id: client_id,
ws_group: '首页'
}).then((webRes) => {
let ddd = {
type: 'login_su***ess',
login_id: webRes.data.login_id
};
this.send(JSON.stringify(ddd));
console.log('发送登录消息', ddd);
this.manual_colse = false;
}).catch((err) => {
console.log('33err', err)
});
}
// 发送
send(data) {
// this.ws.send(data)
if (this.connected) {
this.sendRetryCount = 0;
this.ws.send(data)
} else {
this.sendRetryCount++
setTimeout(() => { }, this.sendRetryCount * 500)
}
}
// 关闭socket连接
close() {
if (this.ws) {
this.ws.close();
this.connected = false; // 更新连接状态
clearInterval(this.heartbeatInterval); // 清除心跳检测定时器
}
}
// 开启心跳检测
start() {
this.heartbeatInterval = setInterval(() => {
this.data = {
type: "ping"
};
this.send(JSON.stringify(this.data));
}, 5000);
}
}
注意点:在webSocket.js
这样的非Vue组件文件中,this
并不指向Vue实例,因此无法直接通过this.$bus
来访问事件总线,所以我这用的是vue.$bus.$emit.
在main.js文件中:我的事件总线是挂载在Vue原型上的,那么我在组件中就可以使用this.$bus
来访问它
Vue.use(ElementUI);
new Vue({
router,
store,
render: h => h(App),
beforeCreate() {
Vue.prototype.$bus = this
}
}).$mount('#app')
在App.vue文件里的mounted
生命周期钩子中执行,在登录成功后调用了SocketService.Instance.connect(this)
来连接WebSocket。
<script>
import SocketService from "./utils/websocket";
import { AutoLoginApi } from "@/request/api";
export default {
mounted() {
const token = localStorage.getItem("token");
if (token) {
AutoLoginApi()
.then(res => {
if (token) {
SocketService.Instance.connect(this);
}
})
.catch(error => {
console.log("自动登录error", error);
});
}
}
};
</script>
在需要监听数据的页面进行this.$bus.$on监听, this.$bus.$off 移除自定义事件监听器。
<script>
export default {
data() {
return {
};
},
beforeDestroy() {
console.log("销毁");
this.stopListening();
},
created() {
this.startListening();
},
methods: {
startListening() {
this.$bus.$on("charge_normal_end", this.on_res_msg_charge_normal_end);
this.$bus.$on("shots_count_change", this.on_res_msg_shots_count_change);
},
stopListening() {
this.$bus.$off("charge_normal_end", this.on_res_msg_charge_normal_end);
this.$bus.$off("shots_count_change", this.on_res_msg_shots_count_change);
},
on_res_msg_charge_normal_end(data) {
//在这里处理逻辑
console.log("输出信息查看", data);
},
on_res_msg_shots_count_change(data) {
console.log("输出信息查看", data);
}
}
};
</script>
最后,在退出登录的时候,关闭webSocket
<script>
import SocketService from "@/utils/websocket";
export default {
data() {
return {
};
},
methods: {
// 退出登录
handle***mand(***mand) {
// 清除token
localStorage.removeItem("token");
// 关闭WebSocket连接
if (SocketService.Instance.connected) {
console.log("关闭WebSocket连接");
SocketService.Instance.ws.close();
}
}
}
};
</script>