[TOC] #### 1. WebSocket 介绍 --- ##### 基本概念 WebSocket 是一种基于 TCP 的全双工通信协议,允许客户端和服务器建立持久连接,实现高效实时数据交换。 全双工通信:客户端和服务器可随时主动发送数据,无需遵循传统 HTTP 的 “请求-响应” 模式 ##### 握手过程 客户端发起握手请求:客户端通过普通的 HTTP 请求向服务器发起 WebSocket 握手请求,这个请求包含了一些特殊的头部,在控制台的请求标头可以看到,例如:`Upgrade:websocket`、`Connection:Upgrade`,以及一个随机的 `sec-websocket-key` 头部。这些头部告诉服务器这是一个 WebSocket 握手请求,并且要升级到 WebSocket 协议 服务器响应握手请求:服务器收到握手请求后,如果支持 WebSocket 协议,就会发送一个 HTTP 101 状态码,表示同意升级到 WebSocket 协议。响应头中也会包含类似的特殊头部,如:`Upgrade:websocket`、`Connection:Upgrade`,以及一个经过计算的 `Sec-Websocket-Accept` 头部,用于验证握手请求的合法性 握手成功,建立连接:一旦客户端收到服务器的握手响应,并验证了其中信息,握手过程就完成了,此时客户端和服务器之间就建立了 WebSocket 连接,可以开始进行实时的双向通信 在握手成功后,客户端和服务器就可以通过 Websocket 连接发送和接收数据,而不再需要普通的 HTTP 请求和响应。这种实时的双向通信方式大大提高了 Web 应用程序的交互性和实时性 #### 2. WebSocket API --- 在浏览器中,JavaScript 提供了原生的 WebSocket API,特别适用于实时应用,如聊天、数据推送等场景。 ##### 创建连接 ```javascript // 创建一个连接,连接失败时会抛出错误(加密协议使用 wss) const ws = new WebSocket("ws://127.0.0.1:2345"); ``` ##### 事件监听 ```javascript // 监听连接事件(连接成功) ws.onopen = function (e) { console.log("WebSocket 连接成功"); console.log(e); } // 监听消息事件(收到服务端消息) ws.onmessage = function (e) { console.log("收到服务端的消息:" + e.data); console.log(e); } // 监听错误事件(连接发生错误) ws.onerror = function (e) { console.log("WebSocket 发生错误"); console.log(e); } // 监听关闭事件(连接关闭) ws.onclose = function (e) { console.log('WebSocket 连接已关闭'); console.log(e); } ``` ##### 发送消息 ```javascript // 支持的参数类型 String、Blob、ArrayBuffer,一般都使用 String ws.send('hello,world') // 实际开发,通常发送的是 json 字符串格式 const data = { type: 'chat', mode: 'text', content: '...' } ws.send(JSON.stringify(data)) ``` ##### socket 对象属性 `ws.readyState` 表示 socket 的连接状态,它的四个值都是 WebSocket 对象的属性 + CONNECTING:0 正在尝试建立连接 + OPEN:1 连接成功 + CLOSING:2 正在关闭连接 + CLOSED:3 连接是关闭状态 ```javascript const ws = new WebSocket("ws://127.0.0.1:2345"); console.log('readyState: ' + ws.readyState); ``` 通过以下命令,可以发现 CONNECTING、OPEN、CLOSING、CLOSED 都是 WebSocket 对象的属性 ```javascript console.dir(WebSocket); ``` 所以,我们可以通过 WebSocket 的属性来判断 socket 的状态,下面代码在重连机制中就可以用到 ```javascript if (ws.readyState === WebSocket.CLOSED) { // ... } ``` ##### socket 对象方法 + ws.send() 发送数据到服务端 + ws.close() 关闭连接 当客户端想要主动关闭连接时,可以调用 `ws.close()` 关闭 ```javascript ws.close() ``` #### 3. 心跳检测 --- WebSocket 是长连接协议,但网络中间设备可能因超时关闭长时间无数据传输的连接。心跳检测通过客户端和服务端定时交换心跳包,模拟活跃通信,防止连接被意外中断。 简而言之:心跳检测的作用是保持连接活跃,避免因长时间无数据传输而被关闭连接 ```javascript // 定时器 id let heartbeatTimer = null // 开始发送心跳包,发送任意数据均可 function heartbeatStart(time = 3000) { heartbeatTimer = setInterval(() => { ws.send(JSON.stringify({ type: 'heartbeat' })) }, time) } // 关闭定时器,取消定时发送心跳包 function heartbeatClear() { if (heartbeatTimer) { clearInterval(heartbeatTimer) heartbeatTimer = null } } ``` 连接成功后开始发送心跳包,关闭连接后停止发送心跳包,代码示例: ```javascript // 监听连接事件(连接成功) ws.onopen = function (e) { console.log("WebSocket 连接成功"); // 开启心跳检测 heartbeatStart() } // 监听关闭事件(连接关闭) ws.onclose = function (e) { console.log('WebSocket 连接已关闭'); // 关闭心跳检测 heartbeatClear() } ``` #### 4. 重连机制 --- WebSocket 重连机制是确保长连接稳定性的关键,比如:在网络波动或服务端重启时自动恢复连接 重连机制应该在连接断开时进行,我们要区分正常断开还是出现异常被迫断开,以避免无限重连 重连方法的核心逻辑:异常断开连接时,执行重连机制尝试重新连接,重新连接成功后清除定时器 ```javascript let ws = new WebSocket("ws://127.0.0.1:2345"); let reconnectTimer = null let reconnectInterval = 5000 function reconnect() { if (ws.readyState === WebSocket.CLOSED) { ws = new WebSocket("ws://127.0.0.1:2345"); } } // 监听连接事件(连接成功) ws.onopen = () => { if (reconnectTimer) { clearInterval(reconnectTimer) reconnectInterval = null } } // 监听关闭事件(连接关闭) ws.onclose = (event) => { if (event.code === 1000) { // 正常关闭,不重连 } else { // 异常断开,触发重连逻辑 console.log('正在尝试重新连接...'); reconnectTimer = setInterval(reconnect, reconnectInterval) } } ``` 在上诉代码中,可发现存在问题,事件监听只能监听到首次连接,无法监听到重新连接后的事件 因为首次进入页面后变量 ws 的值已经确定,事件监听已经完成,重新连接后 ws 变量值变了,事件监听也失效了 此处只是提供一个思路,实际开发中根据项目场景自行修改,代码结构调整后的示例: ```javascript let ws = new WebSocket("ws://127.0.0.1:2345"); let reconnectTimer = null let reconnectInterval = 5000 function reconnect() { if (ws.readyState === WebSocket.CLOSED) { ws = new WebSocket("ws://127.0.0.1:2345"); // 重连后,调用事件监听方法,监听新的 ws 对象 socketEvent() } } socketEvent() function socketEvent() { ws.onopen = () => { } ws.onmessage = (e) => { } ws.onclose = (event) => { } } ``` #### 5. 八股文问题 --- 1、WebSocket 和 HTTP 的主要区别是什么? WebSocket 是全双工通信模式,而 HTTP 是 “请求-响应” 模式 2、WebSocket 如何保证数据传输的安全性? WebSocket 使用 `wss`(WebSocket Secure)协议,它是 WebSocket 协议的加密版本,相当于 HTTPS 3、WebSocket 的心跳检测有什么用? 心跳检测用于保持连接的活跃性,避免长时间无数据传输被关闭连接,还可以用于检测对方是否在线 4、WebSocket 连接过程中的状态码有哪些? WebSocket 连接过程中的状态码有:CONNECTING(0)、OPEN(1)、CLOSING (2)、CLOSED(3)