简介
websocket在前端开发中,是一个必须掌握的技术!你可以不用,但必须掌握!
前几天,就遇到这样一个需求,要求界面的数据通过websocket
实时推送,并且必须支持断网重连、自动心跳!
自动心跳是定期向服务端发送小型数据包,如果一段时间内服务端没有收到心跳响应,系统可能会断开连接。
websokect的API非常简单
// 创建ws连接
const ws = new WebSocket('ws://localhost:8080/test');
ws.onopen = function() {
console.log('WebSocket 连接已经建立。');
ws.send('Hello, server!');
};
ws.onmessage = function(event) {
console.log('收到服务器消息:', event.data);
};
ws.onerror = function(event) {
console.error('WebSocket 连接出现错误:', event);
};
ws.onclose = function() {
console.log('WebSocket 连接已经关闭。');
}
但是,要封装一个支持断网重连、自动心跳的websokect没有那么容易!
封装成功演示
核心优势
我们先看我封装的websokect,首先,最重要的,它的使用方法和官方Api完全一致!零学习成本,上手即用!
import WebSocketClient from "./WebSocketClient"
// 创建实例
const ws = new WebSocketClient('ws://localhost:3200');
// 连接
ws.connect()
// 同原生方法
ws.onclose(()=>{
})
// 同原生方法
ws.onerror(()=>{
})
// 同原生方法
ws.onmessage(()=>{
// 同原生方法
ws.send("自定义发送的数据")
})
// 同原生方法
ws.onopen(()=>{
})
// 关闭连接
ws.close()
效果演示
后端服务创建
我们先使用node创建一个后端服务,安装ws库:
npm install ws
创建node index.js文件,引入WebSocket 服务器
const WebSocket = require("ws");
const wss = new WebSocket.Server({
port: 3200 });
console.log("服务运行在http://localhost:3200/");
wss.on("connection", (ws) => {
console.log("[服务器]:客官您来了~里边请");
ws.send(`[websocket云端]您已经连接云端!数据推送中!`);
let index = 1;
const interval = setInterval(() => {
ws.send(`[websocket]数据推送第${
index}次`);
index ++
}, 1000 * 10);
ws.on("close", () => {
clearInterval(interval); // 清除定时器
console.log("[服务器]:客官下次再来呢~");
});
});
我们启动这个服务
node index.js
现在,我们在前端服务内进行连接测试
前端websokect测试
我们先写前端的相关逻辑
import {
WebSocketClient } from '@/utils/dataDispatcher/WebSocketClient';
const ws = new WebSocketClient('ws://localhost:3200');
// 连接
ws.connect();
// 同原生方法
ws.onclose(() => {
});
// 同原生方法
ws.onerror(() => {
});
// 同原生方法
ws.onmessage(() => {
// 同原生方法
ws.send('自定义发送的数据');
});
// 同原生方法
ws.onopen(() => {
});
启动项目,我们会发现控制台已经有了提示
心跳验证:
等待一段时间后,我们可以看到ws连接里,前端已经发送了多次心跳数据
服务端与客户端也一直在进行数据交互
断网重连验证:
可以看到,当我们断开服务端的时候,断网重连被自动触发。
技术路线
基本框架搭建
export class WebSocketClient {
// #socket链接
private url = '';
// #socket实例
private socket: WebSocket | null = null;
constructor(url: string) {
super();
this.url = url;
}
// >消息发送
public send(message: string): void {
if (this.socket && this.socket.readyState === WebSocket.OPEN) {
this.socket.send(message);
} else {
console.error('[WebSocket] 未连接');
}
}
// !初始化连接
public connect(): void {
if (this.socket && this.socket.readyState === WebSocket.OPEN) {
return;
}
this.socket = new WebSocket(this.url);
// !websocket连接成功
this.socket.onopen = event => {
console.log(`连接成功,等待服务端数据推送[onopen]...`);
};
this.socket.onmessage = event => {
};
this.socket.onclose = event => {
console.log(`连接断开[onclose]...`);
};
this.socket.onerror = event => {
console.log(`连接异常[onerror]...`);
};
}
// >关闭连接
public close(): void {
if (this.socket) {
this.socket.close();
this.socket = null;
}
}
}
上述代码借助官方API实现了一个基本的 WebSocket 客户端,具有以下功能:
- 初始化连接并处理各种 WebSocket 事件(打开、消息、关闭、错误)。
- 发送消息到服务器。
- 关闭连接。
现在,我们开始逐步完善代码,进行封装。
断网重连封装
export class WebSocketClient{
// #socket链接
private url = '';
// #socket实例
private socket: WebSocket | null = null;
// #重连次数
private reconnectAttempts = 0;
// #最大重连数
private maxReconnectAttempts = 5;
// #重连间隔
private reconnectInterval = 10000; // 10 seconds
constructor(url: string) {
super();
this.url = url;
}
// >消息发送
public send(message: string): void {
if (this.socket && this.socket.readyState === WebSocket.OPEN) {
this.socket.send(message);
} else {
console.error('[WebSocket] 未连接');
}
}
// !初始化连接
public connect(): void {
if (this.reconnectAttempts === 0) {
console.log(`初始化连接中...`);
}
if (this.socket && this.socket.readyState === WebSocket.OPEN) {
return;
}
this.socket = new WebSocket(this.url);
// !websocket连接成功
this.socket.onopen = event => {
// 重置重连尝试成功连接
this.reconnectAttempts = 0;
console.log(`连接成功,等待服务端数据推送[onopen]...`);
};
this.socket.onmessage = event => {
};
this.socket.onclose = event => {
if (this.reconnectAttempts === 0) {
console.log(`连接断开[onclose]...`);
}
if (!this.stopWs) {
this.handleReconnect();
}
};
this.socket.onerror = event => {
if (this.reconnectAttempts === 0) {
console.log(`连接异常[onerror]...`);
}
};
}
// > 断网重连逻辑
private handleReconnect(): void {
if (this.reconnectAttempts < this.maxReconnectAttempts) {