什么是WebSocket_如何在javascript中实现实时通信

发布时间 - 2026-01-07 00:00:00    点击率:
WebSocket是独立于HTTP的全双工通信协议,基于TCP长连接,通过HTTP升级握手后切换为二进制帧通信;fetch和XMLHttpRequest无法替代,因其本质是请求-响应模型,不支持持久化双向通信。

WebSocket 不是 HTTP 的升级版,也不是“带状态的 AJAX”;它是一套独立的全双工通信协议,底层基于 TCP,浏览器和服务器一旦建立连接,就保持长链接,双方可以随时互发消息。

WebSocket 连接为什么不能用 fetchXMLHttpRequest 替代

HTTP 协议本身是请求-响应模型:客户端发一次请求,服务端回一次响应,连接随即关闭。即使使用 fetch 配合轮询(polling)或长轮询(long polling),本质仍是反复建连、断连,有延迟、有开销、无法真正“实时”。而 WebSocket 在握手阶段复用 HTTP(发送 Upgrade: websocket 请求),一旦成功,协议就切换为二进制帧通信,不再受限于 HTTP 的 request/response 生命周期。

常见错误现象:

  • fetch('/ws') 试图“打开 WebSocket”,结果返回 405 或 400 —— 因为 fetch 根本不支持 WebSocket 握手
  • setInterval 里每秒 fetch('/api/updates'),后端压力大、前端卡顿、消息延迟固定在 1s 以上

如何用 WebSocket 构造函数建立连接

浏览器原生支持 WebSocket,无需额外库。关键点在于 URL 必须以 ws://(开发)或 wss://(生产)开头,且服务端必须运行 WebSocket 服务(如 Node.js 的 ws 库、Python 的 websockets)。

实操建议:

  • 连接前先检查浏览器支持:if ('WebSocket' in window)
  • URL 中不能带查询参数以外的路径段(如 ws://localhost:3000/chat 可以,但 ws://localhost:3000/chat/ 某些服务端会拒绝)
  • 连接失败不会抛异常,而是触发 onerroronclose,需主动监听
  • 避免在未检查 readyState 的情况下直接调用 send(),否则报错 InvalidStateError
const socket = new WebSocket('wss://echo.websocket.org');

socket.onopen = () => {
  console.log('已连接');
  socket.send('hello server');
};

socket.onmessage = (event) => {
  console.log('收到:', event.data);
};

socket.onerror = (error) => {
  console.error('连接出错:', error);
};

socket.onclose = () => {
  console.log('连接已关闭');
};

send() 能传什么类型?为什么有时发不出去

WebSocket.send() 只接受 stringArrayBufferBlobTypedArray。传 Objectnumber 会静默失败(不报错但服务端收不到),因为 JS 会尝试调用 .toString(),结果可能是 [object Object] 或数字字符串,而非预期 JSON。

常见错误场景:

  • socket.send({ id: 1, msg: 'hi' }) → 实际发送的是 [object Object]
  • socket.send(JSON.stringify(data)) 是正确做法,但记得服务端也要做 JSON.parse()
  • 若需传二进制数据(如图片切片),用 Uint8ArrayArrayBuffer,不要转成 base64 字符串再 send,徒增体积和编码开销

连接断开后如何自动重连?别只靠 onclose

onclose 只告诉你断了,但不区分是网络闪断、服务重启还是用户切后台。单纯在里面立刻 new WebSocket(...) 容易触发雪崩重连(尤其在弱网下)。更稳妥的做法是加退避策略 + 状态锁。

实操要点:

  • 用布尔变量 isConnecting 防止并发多次 new WebSocket
  • 首次重试延时 1s,之后每次翻倍(1s → 2s → 4s),上限建议 30s
  • 超过 5 次失败后暂停自动重连,提示用户手动刷新
  • 监听 visibilitychange 事件:页面隐藏时暂停重连,显示时再检查连接状态

真正难的不是写几行 new WebSocket,而是处理好断网、重连、消息堆积、重复投递、心跳保活这些边界——它们不会出现在“Hello World”例子里,但线上系统天天撞上。


# javascript  # python  # java  # js  # 前端  # node.js  # json  # ajax  # node  # 编码  # 浏览器 


相关栏目: 【 网站优化151355 】 【 网络推广146373 】 【 网络技术251813 】 【 AI营销90571


相关推荐: Android中Textview和图片同行显示(文字超出用省略号,图片自动靠右边)  高配服务器限时抢购:企业级配置与回收服务一站式优惠方案  Laravel如何部署到服务器_线上部署Laravel项目的完整流程与步骤  php嵌入式断网后怎么恢复_php检测网络重连并恢复硬件控制【操作】  如何在建站之星绑定自定义域名?  海南网站制作公司有哪些,海口网是哪家的?  javascript中数组(Array)对象和字符串(String)对象的常用方法总结  JavaScript Ajax实现异步通信  免费制作统计图的网站有哪些,如何看待现如今年轻人买房难的情况?  香港服务器选型指南:免备案配置与高效建站方案解析  php结合redis实现高并发下的抢购、秒杀功能的实例  如何实现javascript表单验证_正则表达式有哪些实用技巧  jimdo怎样用html5做选项卡_jimdo选项卡html5实现与切换效果【指南】  jQuery validate插件功能与用法详解  Laravel如何使用.env文件管理环境变量?(最佳实践)  Laravel怎么配置自定义表前缀_Laravel数据库迁移与Eloquent表名映射【步骤】  高防服务器租用指南:配置选择与快速部署攻略  家族网站制作贴纸教程视频,用豆子做粘帖画怎么制作?  最好的网站制作公司,网购哪个网站口碑最好,推荐几个?谢谢?  品牌网站制作公司有哪些,买正品品牌一般去哪个网站买?  高防服务器:AI智能防御DDoS攻击与数据安全保障  php做exe能调用系统命令吗_执行cmd指令实现方式【详解】  轻松掌握MySQL函数中的last_insert_id()  作用域操作符会触发自动加载吗_php类自动加载机制与::调用【教程】  如何快速使用云服务器搭建个人网站?  如何在IIS7上新建站点并设置安全权限?  如何用低价快速搭建高质量网站?  PHP 实现电台节目表的智能时间匹配与今日/明日轮播逻辑  Java垃圾回收器的方法和原理总结  Laravel Asset编译怎么配置_Laravel Vite前端构建工具使用  php485函数参数是什么意思_php485各参数详细说明【介绍】  西安市网站制作公司,哪个相亲网站比较好?西安比较好的相亲网站?  Laravel如何实现图片防盗链功能_Laravel中间件验证Referer来源请求【方案】  在centOS 7安装mysql 5.7的详细教程  如何在云服务器上快速搭建个人网站?  如何在云主机快速搭建网站站点?  Laravel如何记录日志_Laravel Logging系统配置与自定义日志通道  如何彻底卸载建站之星软件?  什么是javascript作用域_全局和局部作用域有什么区别?  Laravel Blade模板引擎语法_Laravel Blade布局继承用法  Laravel中间件起什么作用_Laravel Middleware请求生命周期与自定义详解  Laravel如何生成API文档?(Swagger/OpenAPI教程)  长沙做网站要多少钱,长沙国安网络怎么样?  小米17系列还有一款新机?主打6.9英寸大直屏和旗舰级影像  高防网站服务器:DDoS防御与BGP线路的AI智能防护方案  微信小程序 input输入框控件详解及实例(多种示例)  Javascript中的事件循环是如何工作的_如何利用Javascript事件循环优化异步代码?  Laravel中的withCount方法怎么高效统计关联模型数量  Laravel如何处理和验证JSON类型的数据库字段  Claude怎样写结构化提示词_Claude结构化提示词写法【教程】