JavaScript 的 WebSocket 使用指南

文章目录

        • [1. WebSocket 介绍](#1. WebSocket 介绍)
        • [2. WebSocket API](#2. WebSocket API)
        • [3. 心跳检测](#3. 心跳检测)
        • [4. 重连机制](#4. 重连机制)
        • [5. 八股文问题](#5. 八股文问题)
1. WebSocket 介绍

基本概念

WebSocket 是一种基于 TCP 的全双工通信协议,允许客户端和服务器建立持久连接,实现高效实时数据交换。

全双工通信:客户端和服务器可随时主动发送数据,无需遵循传统 HTTP 的 "请求-响应" 模式

握手过程

客户端发起握手请求:客户端通过普通的 HTTP 请求向服务器发起 WebSocket 握手请求,这个请求包含了一些特殊的头部,在控制台的请求标头可以看到,例如:Upgrade:websocketConnection:Upgrade,以及一个随机的 sec-websocket-key 头部。这些头部告诉服务器这是一个 WebSocket 握手请求,并且要升级到 WebSocket 协议

服务器响应握手请求:服务器收到握手请求后,如果支持 WebSocket 协议,就会发送一个 HTTP 101 状态码,表示同意升级到 WebSocket 协议。响应头中也会包含类似的特殊头部,如:Upgrade:websocketConnection: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)

相关推荐
jason_yang2 小时前
这5年在掘金的感想
前端·javascript·vue.js
独自破碎E2 小时前
【前序+中序】重建二叉树
java·开发语言
2301_765715142 小时前
C语言轮子制造
c语言·开发语言·制造
量子炒饭大师2 小时前
【C++入门】Cyber骇客的同名异梦——【C++重载函数】(与C的函数差异)
c语言·开发语言·c++·函数重载
charlie1145141912 小时前
现代嵌入式C++教程:if constexpr——把编译期分支写得像写注释 —— 工程味实战指南
开发语言·c++·笔记·学习·嵌入式·现代c++
冰暮流星2 小时前
javascript如何转换为字符串与布尔型
java·开发语言·javascript
LIZhang20162 小时前
c++ 转化句柄,解决多线程安全释放问题
开发语言·c++
2501_948122632 小时前
React Native for OpenHarmony 实战:Steam 资讯 App 个人中心页面
javascript·react native·react.js·游戏·ecmascript·harmonyos
youqingyike2 小时前
Qt 中 QWidget 调用setLayout 后不显示
开发语言·c++·qt