10-WebSocket 实时通信

发布时间:2026/6/24 3:02:20
10-WebSocket 实时通信 WebSocket 实时通信从 HTTP 轮询到 WebSocket掌握浏览器与服务器的全双工实时通信技术学习目标读完本文你将学会理解 WebSocket 与 HTTP 轮询的本质区别掌握 WebSocket API 的完整使用方法实现心跳检测、断线重连等生产级功能对比 WebSocket、SSE、长轮询的适用场景一、为什么需要 WebSocket1.1 HTTP 的局限性HTTP 是请求-响应模型客户端发起请求服务器才能响应。服务器无法主动向客户端推送数据。客户端 ──请求──▶ 服务器 客户端 ◀──响应── 服务器 服务器无法主动说有新消息了1.2 实时通信方案的演进方案原理延迟资源消耗适用场景短轮询客户端定时发送 HTTP 请求取决于轮询间隔高大量无效请求简单场景长轮询服务器挂起请求直到有数据接近实时中连接保持兼容旧浏览器SSE (Server-Sent Events)HTTP 长连接服务器单向推送低低股票行情、新闻推送WebSocketTCP 全双工连接极低低聊天、游戏、协同编辑短轮询: 请求→响应 请求→响应 请求→响应 频繁往返 长轮询: 请求→等待→响应 请求→等待→响应 减少部分往返 SSE: 连接建立→服务器持续推送→推送→推送 单向 WebSocket: 握手一次→双向自由通信 全双工1.3 WebSocket 的优势全双工通信客户端和服务器可同时发送数据低延迟建立连接后无需重复握手低开销数据帧头仅 2-14 字节远小于 HTTP 头跨域支持原生支持 CORS二、WebSocket 协议基础2.1 握手过程WebSocket 连接始于一次 HTTP 升级请求GET /chat HTTP/1.1 Host: server.example.com Upgrade: websocket Connection: Upgrade Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ Sec-WebSocket-Version: 13服务器响应HTTP/1.1 101 Switching Protocols Upgrade: websocket Connection: Upgrade Sec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbKxOo之后TCP 连接从 HTTP 协议切换为 WebSocket 协议。2.2 数据帧结构0 1 2 3 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 -------------------------------------------------------- |F|R|R|R| opcode|M| Payload len | Extended payload length | |I|S|S|S| (4) |A| (7) | (16/64) | |N|V|V|V| |S| | (if payload len126/127) | | |1|2|3| |K| | | ------------------------- - - - - - - - - - - - - - - - | Extended payload length continued, if payload len 127 | - - - - - - - - - - - - - - - ------------------------------- | |Masking-key, if MASK set to 1 | -------------------------------------------------------------- | Masking-key (continued) | Payload Data | -------------------------------- - - - - - - - - - - - - - - - : Payload Data continued ... : - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - | Payload Data continued ... | ---------------------------------------------------------------FIN是否为最后一帧opcode操作码1文本2二进制8关闭9ping10pongMASK客户端发送的数据必须掩码Payload len负载长度0-125 直接表示126 则用后续 2 字节127 用 8 字节三、WebSocket API 详解3.1 创建连接constwsnewWebSocket(wss://echo.websocket.org/);// 连接成功ws.onopen(){console.log(连接已建立);ws.send(Hello Server!);};// 接收消息ws.onmessage(event){console.log(收到:,event.data);};// 连接关闭ws.onclose(event){console.log(连接关闭,event.code,event.reason);};// 发生错误ws.onerror(error){console.error(WebSocket 错误:,error);};3.2 连接状态console.log(ws.readyState);// CONNECTING 0 连接中// OPEN 1 已连接// CLOSING 2 关闭中// CLOSED 3 已关闭3.3 发送数据// 发送文本ws.send(文本消息);// 发送二进制BlobconstblobnewBlob([二进制数据],{type:text/plain});ws.send(blob);// 发送 ArrayBufferconstbuffernewArrayBuffer(8);ws.send(buffer);3.4 关闭连接// 正常关闭code 1000 表示正常关闭ws.close(1000,用户主动关闭);常用关闭码状态码含义1000正常关闭1001终端离开如浏览器关闭1006异常关闭连接意外断开1008策略违反1011服务器错误四、生产级 WebSocket 封装4.1 心跳检测长时间无数据传输中间代理可能断开连接。心跳机制保持连接活跃classHeartbeatWebSocket{constructor(url){this.urlurl;this.wsnull;this.heartbeatInterval30000;// 30 秒this.heartbeatTimernull;}connect(){this.wsnewWebSocket(this.url);this.ws.onopen(){this.startHeartbeat();};this.ws.onmessage(event){if(event.datapong)return;// 忽略心跳响应this.onMessage?.(event.data);};this.ws.onclose(){this.stopHeartbeat();};}startHeartbeat(){this.heartbeatTimersetInterval((){if(this.ws.readyStateWebSocket.OPEN){this.ws.send(ping);}},this.heartbeatInterval);}stopHeartbeat(){clearInterval(this.heartbeatTimer);}}4.2 断线重连classReconnectWebSocket{constructor(url,options{}){this.urlurl;this.reconnectIntervaloptions.reconnectInterval||3000;this.maxReconnectAttemptsoptions.maxReconnectAttempts||5;this.attempts0;this.wsnull;}connect(){this.wsnewWebSocket(this.url);this.ws.onopen(){this.attempts0;console.log(连接成功);};this.ws.onclose(){this.attemptReconnect();};this.ws.onerror(){this.ws.close();};}attemptReconnect(){if(this.attemptsthis.maxReconnectAttempts){console.error(重连次数已达上限);return;}this.attempts;console.log(${this.attempts}秒后尝试重连...);setTimeout(()this.connect(),this.reconnectInterval);}}完整代码见CODE-ADVANCED/10-WebSocket实时通信/websocket-reconnect.js五、实战案例实时聊天室5.1 需求分析多用户实时收发消息显示在线用户列表消息历史记录5.2 客户端实现constchat{ws:null,username:,connect(name){this.usernamename;this.wsnewWebSocket(wss://chat.example.com);this.ws.onopen(){this.send({type:join,username:name});};this.ws.onmessage(event){constmsgJSON.parse(event.data);switch(msg.type){casemessage:this.displayMessage(msg);break;caseuserList:this.updateUserList(msg.users);break;casesystem:this.displaySystem(msg.text);break;}};},send(data){if(this.ws.readyStateWebSocket.OPEN){this.ws.send(JSON.stringify(data));}},sendMessage(text){this.send({type:message,text,from:this.username});}};完整代码见CODE-ADVANCED/10-WebSocket实时通信/websocket-chat.html六、WebSocket vs SSE vs 长轮询┌─────────────────┬──────────────┬──────────────┬──────────────┐ │ 特性 │ WebSocket │ SSE │ 长轮询 │ ├─────────────────┼──────────────┼──────────────┼──────────────┤ │ 通信方向 │ 双向 │ 服务器→客户端 │ 双向伪 │ │ 协议 │ TCP (ws/wss) │ HTTP │ HTTP │ │ 实时性 │ 极高 │ 高 │ 中 │ │ 浏览器兼容 │ IE10 │ IE 不支持 │ 全部 │ │ 自动重连 │ 需手动实现 │ 原生支持 │ 需手动实现 │ │ 二进制数据 │ 支持 │ 不支持 │ 需 Base64 │ │ 多域名连接 │ 有限制 │ 无限制 │ 无限制 │ │ 防火墙穿透 │ 可能受阻 │ 易穿透 │ 易穿透 │ └─────────────────┴──────────────┴──────────────┴──────────────┘选择建议需要双向实时聊天、游戏→ WebSocket仅需服务器推送股票、日志→ SSE需要兼容旧浏览器→ 长轮询二、常见误区与注意点误区正确做法WebSocket 可以替代所有 HTTPWebSocket 用于实时场景REST API 仍适合 CRUD连接永不关闭页面切换/网络变化时连接会断开需处理重连不需要考虑兼容性IE9 及以下不支持需准备降级方案所有数据都用 WebSocket文件上传等大流量操作仍用 HTTP 更合适忽略错误处理必须处理 onerror、onclose实现重连策略三、动手练习练习 1心跳检测实现在基础 WebSocket 连接上添加心跳机制如果 3 次心跳无响应则认为连接已断开触发重连。练习 2简易协同白板使用 WebSocket 实现多人实时绘图鼠标移动时发送坐标其他客户端实时绘制。四、AI 辅助学习4.1 本节知识点的 AI 提问模板“WebSocket 的 Sec-WebSocket-Key 是如何生成的”“如何在 WebSocket 中实现消息确认机制ACK”“WebSocket 连接数有浏览器限制吗”4.2 用 AI 验证你的理解尝试向 AI 描述 WebSocket 握手过程让它判断你的理解是否正确。4.3 警惕 AI 的常见错误AI 可能混淆 WebSocket 和 Socket.IO后者是库不是协议AI 可能忘记提到 WebSocket 的掩码机制五、配套代码本文示例代码位于CODE-ADVANCED/10-WebSocket实时通信/文件名说明websocket-basic.htmlWebSocket API 基础演示websocket-chat.html实时聊天室完整实现websocket-reconnect.js断线重连与心跳封装六、本章小结WebSocket 通过 HTTP 升级握手建立 TCP 全双工连接心跳检测和断线重连是生产环境的必备功能WebSocket 适合双向实时场景SSE 适合单向推送注意处理连接状态、错误情况和浏览器兼容性如果本文对你有帮助欢迎点赞、收藏、关注专栏。有任何问题可以在评论区交流