WebSocket连接失败主因是地址解析在客户端,localhost/127.0.0.1仅指向本机,跨设备需用服务端实际可达IP(如192.168.x.x)并确保防火墙放行;前端应通过后端注入全局变量(如window.WS_SERVER)动态获取WS地址,避免硬编码或location拼接。

WebSocket连接地址当然可以用IP,但直接写死 127.0.0.1 或 localhost 在跨设备访问时必然失败——这不是浏览器兼容性问题,而是网络层根本连不到目标机器。
WebSocket地址写localhost或127.0.0.1为什么在手机上连不上
因为 localhost 永远指向“当前设备自身”。你在电脑浏览器里访问 ws://localhost:8080,连的是你本机;但在同一Wi-Fi下的手机里打开页面,它执行的仍是 ws://localhost:8080,结果是尝试连接手机自己的 8080 端口(显然没服务)。
- 现象:手机控制台报错
WebSocket connection to 'ws://localhost:8080/' failed,但电脑能通 - 本质:URL 解析发生在客户端,不是服务端;IP 必须对客户端可达
- 正确做法:用服务端实际可被访问的 IP(如内网
192.168.x.x)或域名,且确保防火墙/路由器放行对应端口
前端如何动态获取WebSocket服务器地址
不能靠 window.location 直接拼,因为页面 URL 和 WebSocket 后端地址往往不同源(比如页面走 Nginx 反代,WebSocket 走直连);更可靠的方式是后端注入或配置中心下发。
WebSocket 8.18.2 是该协议规范的一个重要迭代版本,主要优化了连接稳定性与数据传输效率。它通过全双工通信机制,允许客户端与服务器在单一长连接上实时交换数据,大幅降低传统 HTTP 轮询的开销。该版本增强了心跳保活、自动重连及二进制帧传输能力,适用于即时通讯、在线游戏及金融行情推送等低延迟场景,为开发者提供更可靠的实时网络交互基础。
- 推荐方案:后端在 HTML 模板中注入一个全局变量,例如
window.WS_SERVER = "ws://192.168.1.100:8080/ws" - 次选方案:前端读取
/api/config接口返回的wsUrl字段(注意该接口本身需跨域或同源) - 不推荐方案:用
location.hostname拼接(ws://${location.hostname}:8080),容易因端口/协议不匹配失败 - 特别注意:
ws://对应 HTTP,wss://对应 HTTPS;若页面是https://,浏览器会禁止降级使用ws://
Spring Boot 中获取客户端真实 IP 的坑点
WebSocket 连接建立后,Session.getBasicRemote() 或 Session.getUserProperties() 默认拿不到真实 IP——因为握手请求(HTTP Upgrade)经过 Nginx / SLB 时,原始 IP 被覆盖了。
- 必须确保反代层透传头信息,例如 Nginx 配置含:
proxy_set_header X-Real-IP $remote_addr;和proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; - Java 端不能只调
session.getAsyncRemote().getRemoteAddress(),它返回的是代理出口 IP - 正确路径:从
Session的getUserProperties()中提取javax.websocket.server.ServerEndpointConfig.MESSAGE_CONTEXT,再转成HttpServletRequest,最后用getHeader("X-Real-IP")或getRemoteAddr()(后者仅在无代理时可靠) - Netty 场景下,IP 必须在
HttpServerCodec阶段、WebSocketServerProtocolHandler之前捕获,否则握手完成就丢失上下文
真正容易被忽略的是:WebSocket 的 IP 获取和 HTTP 完全不是一回事——它没有标准的 request 对象生命周期,所有“真实 IP”都依赖于 Upgrade 请求头的完整透传,而这个链路里任何一个环节漏配 X-Real-IP,拿到的就只是最后一跳的 IP。

















