WebSocket是HTML5多人联机游戏最合适的网络方案,因其低延迟、原生支持、全双工通信;HTTP轮询或SSE不适用实时对战,fetch/XHR存在连接开销大、无状态、无法主动推送等问题。

HTML5 游戏做多人联机,核心不是选哪个引擎,而是先搭稳网络通信骨架——WebSocket 是当前最直接、低延迟、浏览器原生支持的方案,HTTP 轮询或 Server-Sent Events 基本不适合实时对战类游戏。
为什么不用 XMLHttpRequest 或 fetch 做实时同步
这类请求本质是“发一次、等一次”,哪怕加了长轮询,也会带来明显延迟和连接开销。玩家移动、射击、碰撞判定这些操作要求 100ms 内完成端到端响应,而典型 fetch 请求从建立连接、发送、服务端处理、返回,轻松突破 200–400ms(尤其在弱网下)。
-
fetch每次都要重连 TCP,无状态,无法维持玩家在线身份 - 服务端无法主动推送状态变更(比如队友突然死亡),只能靠客户端不断问“死了没?”
- 频繁请求易触发浏览器并发限制(通常 6 个同域连接),卡住资源加载
WebSocket 连接建立与心跳保活的关键点
浏览器发起 new WebSocket('wss://game.example.com') 后,服务端必须完成 HTTP 升级握手;但真正上线后,连接可能因 NAT 超时、WiFi 切换、休眠被静默断开——这不会立刻触发 onclose,得靠心跳探测。
- 客户端每 25 秒发一次
ping消息(如{"type":"ping"}),服务端收到立即回{"type":"pong"} - 客户端设 5 秒超时:发了
ping但没收到pong,就主动close()并重连 - 服务端也要检测连续 2 次未收到
ping,清理该连接对应的游戏实体(如playerId状态置为离线) - 别用
setInterval直接发包——要等上一个send()成功回调后再计时下一次,避免堆积
服务端如何区分并路由玩家消息(以 Node.js + ws 库为例)
ws 库本身不维护用户会话,每个 WebSocket 实例只是裸连接。你必须自己绑定玩家身份,并在收到消息时明确知道“谁发的、发给谁、要不要广播”。
立即学习“前端免费学习笔记(深入)”;
- 连接成功后,服务端生成唯一
playerId(如crypto.randomUUID()),存入 Map:connections.set(playerId, ws) - 登录消息(如
{"type":"login","name":"Alice"})需校验 token 或 sessionId,通过后再关联playerId - 移动消息(
{"type":"move","x":120,"y":85})应带playerId,服务端更新该玩家坐标,再向除自己外的所有在线玩家广播精简后的状态(如{"type":"state","id":"abc123","x":120,"y":85,"ts":1715829341}) - 避免直接转发原始消息——攻击者可伪造
playerId冒充他人;所有输入必须校验字段类型、数值范围、频率(如每秒最多 10 次move)
真正的难点不在连上,而在断开后怎么恢复——比如玩家切后台 30 秒再回来,角色位置是否漂移?技能冷却是否错乱?这些需要客户端做本地预测 + 服务端权威校验,而校验依据,就是你从第一步开始就严格设计的消息结构和时序标记(ts 或 sequenceId)。











