ERR_CONNECTION_REFUSED 根本原因是服务端未启动或未在目标端口监听,而非网络问题;它表示TCP连接被内核拒绝,因无进程处于LISTEN状态,常见于WebSocket、本地开发服务器等场景。

WebSocket 不是 HTTP 的替代品,而是一次“握手成功后就彻底脱离 HTTP”的独立协议。它解决的是「服务端无法主动推消息」和「每次通信都要重连」这两个硬伤,不是为了写得更酷,而是业务真需要——比如聊天室里新消息秒达、交易页面价格实时跳动、扫码登录时手机一确认网页立刻刷新。
WebSocket 连接为什么总是报 ERR_CONNECTION_REFUSED 或 net::ERR_CONNECTION_CLOSED
这类错误基本和协议无关,90% 是服务端根本没在监听,或客户端 URL 写错。
-
ws://localhost:3000要求服务端确实在 3000 端口启动了 WebSocket 服务(比如用ws库的new WebSocket.Server({ port: 3000 })),不能只跑着一个 Express HTTP 服务器就以为能连上 - 前端写成
ws://127.0.0.1:3000但服务端绑定的是localhost(或反之),某些系统 DNS 解析会失败;统一用localhost最稳 - 服务端监听了
0.0.0.0:3000,但你本地防火墙或云服务器安全组没放开该端口,浏览器发包直接被拦 - 开发时用
ws://,上线必须换wss://,否则现代浏览器会直接拒绝连接(不报错,静默失败)
客户端 WebSocket 实例创建后,onopen 死活不触发
这不是代码写错了,而是连接卡在握手阶段。WebSocket 握手本质是一次 HTTP 请求,所以所有 HTTP 常见问题都会复现。
WebSocket 8.18.2 是该协议规范的一个重要迭代版本,主要优化了连接稳定性与数据传输效率。它通过全双工通信机制,允许客户端与服务器在单一长连接上实时交换数据,大幅降低传统 HTTP 轮询的开销。该版本增强了心跳保活、自动重连及二进制帧传输能力,适用于即时通讯、在线游戏及金融行情推送等低延迟场景,为开发者提供更可靠的实时网络交互基础。
- 检查浏览器控制台 Network 标签页,找到那个
ws://...请求,看它的状态码是不是101 Switching Protocols;如果不是(比如是 404、403、502),说明服务端没正确响应升级请求 - 服务端用了反向代理(Nginx / Caddy),但没配透传 WebSocket 头部:
Upgrade和Connection字段必须显式转发,否则握手失败 - 服务端收到连接后立即
close()(比如鉴权失败未返回错误帧而是直接断连),此时浏览器只会触发onclose,不会进onopen -
new WebSocket(url)后立刻调send(),但连接还没建立完成,会报InvalidStateError: Failed to execute 'send' on 'WebSocket': Still in CONNECTING state—— 必须等onopen回调里再发
Node.js 用 ws 库时,message 事件收不到字符串
ws 默认把所有 message 当作 Buffer 对象传入,不是自动转成字符串。这是性能设计,不是 bug。
- 简单场景:在事件回调里手动
message.toString(),但注意二进制帧(如图片上传)不能这么转 - 稳妥做法:用
ws的binaryType配置或判断typeof message === 'string',再分支处理 - 服务端广播给所有人时,别直接
client.send(data),要先检查client.readyState === WebSocket.OPEN,否则会抛错中断后续循环 - 如果客户端发的是 JSON 字符串,服务端建议加
try/catch包裹JSON.parse(),非法 JSON 会导致整个message事件处理器崩溃,连接卡死
真正难的从来不是“怎么连上”,而是连接断了之后要不要重连、什么时候重连、重连时怎么同步状态、怎么避免重复投递消息。这些逻辑不会出现在任何 new WebSocket() 示例里,但线上系统每天都在为它们补丁。

















