type
status
date
slug
summary
tags
category
icon
password
「WebSocket在前端开发中,是一项至关重要的技术!即使你当前项目用不到,也必须熟练掌握!」
最近,我遇到了一个典型的需求:界面数据需要通过
WebSocket进行实时推送,并且该连接必须支持**「断网重连」和「自动心跳」**机制。❝ 自动心跳:指客户端定期向服务端发送小型数据包以维持连接。若服务端在一定时间内未收到心跳响应,则可能认为连接已断开。 ❞
原生WebSocket的API相当简洁:
然而,要封装一个同时支持断网重连和自动心跳的WebSocket客户端,并非易事。本文将详细介绍如何实现这一目标。
封装成果演示
核心优势
首先,我们来看一下我封装的
WebSocketClient。其最大的优势在于,它的使用方法与原生WebSocket API完全一致,实现了零学习成本,即插即用!效果演示
后端服务搭建
我们首先使用Node.js和
ws库创建一个简单的WebSocket后端服务。安装
ws库:创建
index.js文件,并引入WebSocket服务器:启动服务:
现在,我们可以在前端项目中进行连接测试。
前端WebSocket测试
在前端项目中,我们引入并使用封装好的
WebSocketClient:启动前端项目,观察控制台输出。
图示:控制台显示WebSocket成功连接的日志
心跳验证:
等待一段时间,可以看到WebSocket连接中,前端会周期性地发送心跳数据。
图示:浏览器开发者工具网络面板显示前端发送的心跳包
服务端与客户端持续进行数据交互。
图示:浏览器开发者工具网络面板显示客户端与服务端的数据交互日志
断网重连验证:
当我们手动断开后端服务(例如,停止Node.js服务),前端的断网重连机制会被自动触发。
图示:演示断开服务端后,前端WebSocket自动尝试重连的过程
技术实现详解
基本框架搭建
首先,我们搭建一个基础的
WebSocketClient类,它封装了原生的WebSocket操作。上述代码实现了一个基础的WebSocket客户端,具备:
- 初始化连接并处理原生WebSocket事件(open, message, close, error)。
- 向服务器发送消息。
- 关闭连接。
接下来,我们将逐步完善这个类,加入断网重连和自动心跳功能。
封装断网重连机制
为了实现断网重连,我们需要引入重连尝试次数、最大重连次数和重连间隔等概念。
核心逻辑说明:
reconnectAttempts:记录当前重连次数。
maxReconnectAttempts:设置最大允许的重连次数。
reconnectInterval:设置重连的时间间隔。可以采用固定间隔或指数退避策略(如示例中Math.pow(2, this.reconnectAttempts - 1)),后者能避免在服务器故障时对服务器造成短时冲击。
stopWsManually:布尔标志,用于区分是意外断开还是用户主动调用close()方法关闭。
handleReconnect():在onclose事件中(且非手动关闭时)调用。如果未达到最大重连次数,则在指定间隔后尝试重新调用connect()。
- 连接成功:
onopen事件触发时,重置reconnectAttempts为0。
- 手动关闭:调用
close()方法时,设置stopWsManually = true,这样onclose事件触发时不会执行重连逻辑。
封装自动心跳机制
自动心跳用于保持连接活跃并检测连接状态。客户端定期发送心跳消息,服务端通常会响应或仅作记录。若客户端在一定周期内未成功发送或未收到服务端响应(如果设计为需要响应),则可认为连接异常。
实现思路:
- 连接建立后,启动定时器,定期发送心跳消息。
- 每次成功发送消息(包括心跳或业务消息)或收到服务器消息后,可以重置心跳定时器,表示连接仍然活跃。
- 如果心跳发送失败或长时间未收到任何消息(更复杂的场景),则可能需要主动关闭并触发重连。
心跳机制要点:
startHeartbeat():连接成功 (onopen)后启动。使用setInterval定期发送预设的heartbeatMessage。
stopHeartbeat():清除心跳定时器。在连接关闭 (onclose)、手动调用close()或启动新的心跳前调用。
resetHeartbeat():当收到服务器消息 (onmessage)时调用,表示连接活跃,重新计时心跳。这是一种常见的优化,避免在频繁通信时不必要的额外心跳。
- 心跳消息:
heartbeatMessage可以自定义。通常是一个小JSON字符串,表明其类型为心跳。
触发原生API风格的回调
为了让封装后的
WebSocketClient使用起来和原生API一致(如ws.onopen = () => {}),我们需要实现一个简单的事件分发机制。这里我们借鉴EventDispatcher模式。现在,让
WebSocketClient继承EventDispatcher:通过继承
EventDispatcher并使用其addEventListener和dispatchEvent方法,我们就能以ws.onopen(() => {})的方式注册和触发回调了。❝ 关于EventDispatcher的更详细实现原理,可以参考设计模式中的观察者模式或发布-订阅模式。原文提及的链接:https://juejin.cn/post/7358518759118700607 提供了另一种实现思路。 ❞
完整代码示例
TypeScript 版本 (WebSocketClient.ts)
EventDispatcher.ts (TypeScript)JavaScript (ES6 Classes) 版本
WebSocketClient.jsEventDispatcher.js (JavaScript)总结与展望
本文详细介绍并实现了一个增强版的
WebSocketClient,它完美支持了断网重连和自动心跳两大核心功能。更重要的是,其API设计与原生WebSocket保持高度一致,开发者可以无缝迁移,开箱即用,极大地降低了学习和使用成本。尽管此封装已相当完善,但仍有可优化之处:
- 配置灵活性:目前如最大重连次数、重连间隔、心跳间隔和心跳内容等都是硬编码的。可以考虑将它们作为构造函数的可选参数传入,使客户端适应更多样化的场景。
- 错误处理与通知:可以增加更细致的错误类型和通知机制,例如当达到最大重连次数后,派发一个特定的“永久断开”事件。
- 背压处理:在极高频率消息场景下,考虑消息队列和背压处理机制。
- 作者:90_blog
- 链接:https://blog.tri7e.com/article/other_map
- 声明:本文采用 CC BY-NC-SA 4.0 许可协议,转载请注明出处。
