WebSocket的介绍:
WebSocket 是一种在客户端和服务器之间进行全双工、双向通信的协议。它是基于 HTTP 协议,但通过升级(HTTP 升级请求)将连接转换为 WebSocket 协议,从而提供更高效的实时数据交换。
WebSocket 的特点:
-
双向通信:与传统的 HTTP 协议只能从客户端向服务器发送请求并等待响应不同,WebSocket 可以实现服务器主动向客户端推送数据,支持双向通信。
-
持久连接:WebSocket 连接建立后,它是持久的,可以在不重新建立连接的情况下进行多次数据交换。相比于传统的 HTTP 每次请求都需要建立新的连接,WebSocket 减少了很多开销。
-
实时性:由于 WebSocket 的全双工通信特性,它非常适合需要实时更新数据的应用场景,如即时聊天、在线游戏、股票行情等。
-
低延迟:WebSocket 建立连接后,数据可以随时在客户端和服务器之间交换,而且没有 HTTP 协议中的请求和响应过程,因此延迟非常低。
-
协议格式:WebSocket 协议位于应用层与 TCP 层之间,它的标准端口是 80(非加密连接)和 443(加密连接)。
WebSocket 工作原理:
- 连接建立:客户端发起一个 HTTP 请求,并通过 HTTP 升级请求(
Upgrade
请求头)向服务器请求升级协议为 WebSocket。 - 协议升级:如果服务器支持 WebSocket 协议,它会响应
101 Switching Protocols
,并升级为 WebSocket 协议。此时,WebSocket 连接建立成功。 - 数据交换:一旦连接建立,客户端和服务器可以在同一连接上发送和接收消息,直到连接被关闭。
- 连接关闭:无论是客户端还是服务器,都可以主动发起关闭连接。连接关闭时,双方会互相发送关闭帧(
Close Frame
)来通知对方。
项目需求:
由于最近项目上的大屏接口要换成WebSocket进行实时数据展示,于是需要对WebSocket进行封装,主要目标是要实现与后端持续保持心跳连接,不要让WebSocket中断;例如每10秒就要和后端通讯一次,发送和后端沟通好固定的心跳标识符,后端拿到心跳标识符就会持续保持连接,如果一直没有收到前端返回的心跳标识符,那么就会中断WebSocket的连接。
源代码
export default class WebSocketClient {
constructor(url, callback) {
this.url = url; // WebSocket 服务器的 URL
this.callback = callback; // 回调方法,用于接收数据
this.ws = null; // WebSocket 实例
this.heartbeatInterval = 20000; // 心跳间隔(20秒)
this.pingTimeout = 10000; // ping 超时时间(10秒)
this.heartbeatTimer = null; // 用于存储心跳定时器
this.pingTimer = null; // 用于存储 ping 超时定时器
this.reconnect = true; // 用于判断是否需要重连
}
// 启动 WebSocket 连接
start() {
this.ws = new WebSocket(this.url);
this.ws.onopen = () => {
console.log("WebSocket连接成功");
this.reconnect = true; // 连接成功,允许重连
this.startHeartbeat(); // 连接成功后开始心跳
};
this.ws.onmessage = (event) => {
this.callback(event.data); // 调用回调方法
};
this.ws.onerror = (error) => {
console.error("WebSocket异常:", error);
};
this.ws.onclose = (event) => {
console.log("WebSocket关闭.");
clearInterval(this.heartbeatTimer); // 清除心跳定时器
clearTimeout(this.pingTimer); // 清除 ping 超时定时器
if (this.reconnect && event.code !== 1000) { // 如果是非正常关闭,进行重连
console.log("尝试重新连接...");
setTimeout(() => {
this.start(); // 5秒后重新连接
}, 5000);
}
};
}
// 发送数据到服务器
send(message) {
if (this.ws && this.ws.readyState === WebSocket.OPEN) {
this.ws.send(message);
} else {
console.error("消息发送失败.");
}
}
// 启动心跳机制
startHeartbeat() {
this.heartbeatTimer = setInterval(() => {
if (this.ws.readyState === WebSocket.OPEN) {
this.send(JSON.stringify({ type: "heartbeat", data: "pong" })); // 与后端约定的心跳标识符,用于保持持续连接
}
}, this.heartbeatInterval);
// 设置 ping 超时机制
this.pingTimer = setTimeout(() => {
if (this.ws.readyState !== WebSocket.OPEN) {
console.error("超时关闭连接.");
this.ws.close();
}
}, this.pingTimeout);
}
// 主动关闭连接
close() {
this.reconnect = false; // 主动关闭时不再进行重连
if (this.ws) {
this.ws.close(1000, 'Closed by client'); // 主动关闭时使用 code 1000 表示正常关闭
}
}
}
用法
import WebSocketClient from '@/request/ws'
export default {
data(){
return{
wsClient:null
}
},
mounted(){
this.wsClient = new WebSocketClient('ws://192.168.31.21:8090/ws', this.getWSMessage);
this.wsClient.start()
},
methods:{
getWSMessage(data){
console.log(data,'ddddddddddddddd')
},
sendMessage(){
let obj = { type: "555", data: "111111" }
this.wsClient.send(JSON.stringify(obj))
}
},
beforeDestroy() {
this.wsClient.close()
}
}