原生javascript实现websocket通信核心是正确建连、状态管理与可控重连:必须用ws://或wss://协议创建实例,监听onopen/onmessage/onclose/onerror四事件,send前校验readystate===1,重连需指数退避并防连接风暴。

原生 JavaScript 实现 WebSocket 通信,核心就三件事:正确创建连接、合理处理状态变化、避免盲目重连。直接上手写 new WebSocket() 很容易,但生产环境里多数问题出在连接管理逻辑上,不是协议用错,而是状态没兜住。
WebSocket 构造函数的 URL 和协议必须匹配后端
浏览器只认 ws:// 和 wss:// 两种前缀,不能写成 http:// 或漏掉端口。比如后端跑在 localhost:8080 且启用了 WebSocket 协议,那前端必须写:
const socket = new WebSocket("ws://localhost:8080");
常见错误现象:
- 控制台报
WebSocket connection to 'http://...' failed—— URL 写成了http协议 - 报
net::ERR_CONNECTION_REFUSED—— 后端没启动,或端口不对,或服务未暴露 WebSocket 路径(如 Nginx 没配Upgrade头) - 报
net::ERR_SSL_PROTOCOL_ERROR—— 开发环境用了wss://但没配 HTTPS,应改用ws://
onopen / onmessage / onclose / onerror 四个事件必须显式监听
不监听 onerror 就等于放弃诊断连接失败原因;不检查 readyState 就调 send() 会静默失败。示例中常省略防御逻辑,但真实场景必须补上:
socket.onopen = () => {
console.log("已连接,readyState =", socket.readyState); // 应为 1
};
socket.onmessage = (event) => {
try {
const data = JSON.parse(event.data);
console.log("收到消息", data);
} catch (e) {
console.warn("非 JSON 消息", event.data);
}
};
socket.onclose = (event) => {
console.log("连接关闭,code=", event.code, "reason=", event.reason);
};
socket.onerror = (event) => {
console.error("WebSocket 错误", event);
};
关键点:
-
onmessage收到的event.data总是字符串,JSON 需手动JSON.parse() -
onclose的event.code是标准关闭码(如1000正常关闭,1006异常断开),比单纯打日志更有诊断价值 -
onerror不传具体错误对象,只触发事件,所以得靠onclose或网络工具定位根本原因
重连不能靠 onclose 里直接 new WebSocket()
这是最常踩的坑:在 onclose 回调里立刻调 initWebSocket(),会导致连接风暴。因为 onclose 在断网、服务宕机等场景下会高频触发,而每次触发都新建实例,浏览器可能瞬间打出几十个连接请求。
正确做法是加退避策略和开关控制:
let isConnecting = false;
let retryCount = 0;
const MAX_RETRY = 5;
const BACKOFF_MS = [1000, 3000, 5000, 10000, 15000];
function connect() {
if (isConnecting || socket?.readyState === WebSocket.OPEN) return;
isConnecting = true;
socket = new WebSocket("ws://localhost:8080");
socket.onopen = () => {
retryCount = 0;
isConnecting = false;
};
socket.onclose = () => {
if (retryCount
<p>注意:</p>
- 用
isConnecting防止并发重复建连 - 用
retryCount控制最大重试次数,避免无限循环 - 延迟递增(backoff),不是固定 3 秒轮询
- 不要在
onerror里重连——它不保证连接已断,只是某次操作失败
心跳必须由客户端主动发,且要防 send 报错
服务器靠心跳判断客户端是否存活,但客户端发心跳前必须确认 socket.readyState === WebSocket.OPEN,否则 send() 会抛异常并终止脚本。
推荐写法:
function startHeartbeat() {
clearInterval(socket.heartbeat);
socket.heartbeat = setInterval(() => {
if (socket.readyState === WebSocket.OPEN) {
try {
socket.send(JSON.stringify({ type: "beat" }));
} catch (e) {
console.warn("心跳发送失败", e);
}
}
}, 30000);
}
容易忽略的细节:
- 心跳间隔通常设为 20–30 秒,太短增加无谓流量,太长导致服务器过早踢人
- 必须用
try/catch包裹send(),因为即使readyState是OPEN,底层 TCP 也可能已中断(浏览器来不及更新状态) - 心跳消息体尽量轻量,纯文本或最小 JSON,别塞大对象或时间戳字符串
真正难的不是连上 WebSocket,而是让连接在弱网、切后台、页面刷新、服务重启等各种现实条件下保持可用。状态判断、错误归因、重试节流、心跳容错——这些逻辑堆叠起来,才是实际项目里 WebSocket 能不能稳住的关键。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











