WebSocket 连不上?五个原因的排查顺序

2026-11-05约 8 分钟网络工具涉及 4 个工具

WebSocket 的失败很少是代码写错 —— 多数卡在握手阶段,而握手由浏览器与中间设备共同把关。五个原因按出现频率排列,前两个占了大多数。

核心要点
  • HTTPS 页面里连 ws:// 会被浏览器按混合内容直接拦掉,必须换成 wss://,本地调试才用 http 页面
  • 多数框架默认只接受同源或白名单里的 Origin,而浏览器握手带的是本站域名,很容易被判 403
  • Nginx 需要显式转发 Upgrade 与 Connection 头,否则握手根本到不了后端应用
  • 握手既不 open 也不 error 时,通常是链路被中间设备静默丢弃,这时候该查网络而不是改代码
  • 浏览器能设的请求头非常有限,需要 token 或 Cookie 鉴权的接口用网页工具连不上,得换成客户端代码

#先判断失败发生在哪个阶段

WebSocket 的失败分两个阶段:握手没成功,或者握手成功但连接立刻断开。 两者的原因完全不重叠,混淆了就会在错误的方向上改代码。

判据很直接:日志里有没有出现「已连接」。没有就是握手失败,有就是连上之后断的。

阶段表现排查方向
握手失败没有「已连接」记录,只有 error协议、Origin、路径、代理、证书
连上就断有「已连接」随即 close服务端逻辑、心跳、鉴权超时
一直连接中既不 open 也不 error链路被中间设备丢弃

用 WebSocket 测试 时,握手超过 10 秒没完成,日志会主动提示一次 —— 这个提示就是为「一直连接中」这种情况准备的。

#混合内容是第一位原因

HTTPS 页面里连 ws:// 会被浏览器直接拦掉,这不是服务端拒绝,是浏览器根本没发出去。 它属于混合内容策略,报错通常出现在控制台而不是网络面板。

规则很简单:

  • 页面是 https://,连接必须用 wss://
  • 页面是 http://,ws:// 与 wss:// 都可以

所以「本地能连、线上连不上」的经典组合,往往就是本地用 http 页面配了 ws://。线上换成 wss 之后,如果服务端没有配置 TLS,就是另一个问题了(证书部分会说)。

注意

混合内容是浏览器层面的拦截,服务端日志里什么都不会留下。如果服务端「看不到任何连接尝试」,先检查页面协议,别去查服务端。

#Origin 校验:服务端主动拒绝

多数 WebSocket 框架默认只接受同源或白名单里的 Origin,而浏览器发起的握手带的是发起页面的域名。 用一个在线工具去连生产环境的接口,Origin 就是工具的域名,被拒是正常的。

这类失败的典型特征是:握手返回 403,且服务端日志里能看到明确拒绝记录 —— 与服务端「根本没收到」正好相反。

处理方式取决于你站在哪一边:

  • 如果你是服务端:把测试用的 Origin 加进白名单,或者对公开接口关掉 Origin 校验
  • 如果你是调用方:换成能设 Origin 的客户端(代码里的 WebSocket 客户端通常可设,浏览器里不行)
说明

Origin 校验不是安全认证。它可以被非浏览器客户端随意伪造,防的是「其他网站借用用户浏览器连你的服务」,不是防「有心人直接连」。

#路径与代理:握手到不了后端

两个基础设施问题占这一类的大半:路径写错,以及反向代理没有转发升级头。 它们都表现为「连不上」,但修法完全不同。

路径问题:多数库默认挂在 /ws 或 /websocket,只填 wss://host 往往返回 404。带上完整路径再试一次。

代理问题更隐蔽:Nginx 需要显式转发 Upgrade 与 Connection 头,否则请求会被当成普通 HTTP 请求处理,握手到不了后端。

NGINX
# 关键在两行 Upgrade / Connection,缺了握手永远不成功
location /ws {
    proxy_pass http://127.0.0.1:8080;
    proxy_http_version 1.1;
    proxy_set_header Upgrade $http_upgrade;
    proxy_set_header Connection "upgrade";
}

注意 proxy_http_version 1.1 也不能少 —— HTTP/1.0 不支持协议升级。Cloudflare 之类的 CDN 需要单独开启 WebSocket 支持。

#证书不被信任:自签的直接失败

wss:// 走的是标准 TLS 握手,自签证书会直接失败,浏览器不给「继续访问」的机会。 这和访问自签 HTTPS 网站时的体验不同,那里至少还能点「高级 → 继续」。

排查办法:用浏览器直接打开 https:// 的那个域名,看证书是否受信任。如果浏览器也报警,那 wss 必然失败。

内网自签证书的场景,可行的做法是让客户端信任该证书(导入根证书),或者用 http 页面配 ws:// 做本地调试。

#顺手确认域名与端口

握手失败也可能是最基础的问题:域名解析错了,或者目标端口根本没在监听。 这两项用工具几分钟就能排除,比读代码快。

按顺序排一遍:

  • 用 DNS 查询 确认域名解析到预期的 IP —— 尤其刚改过解析时,TTL 缓存会让不同网络环境拿到不同结果
  • 用 端口大全 确认目标端口是否常用服务端口,以及防火墙该放行什么。wss 走 443、ws 走 80,但自定义端口也很常见(如 8080、3000)
  • 用 IP 地址查询 判断解析出来的是公网还是私网地址。如果连的是 10.x、172.16-31.x、192.168.x 这类私有地址,从公网环境连必然不通
技巧

浏览器直连目标服务器,消息不经过任何中转 —— 好处是没有中间人,代价是目标服务器能看到你的真实 IP。连陌生地址前,先确认这个地址可信。

#什么时候该用哪个工具

你想确认的事用哪个关键点
握手能不能成功WebSocket 测试只处理文本帧,不支持自定义头
域名解析到哪个 IPDNS 查询TTL 决定缓存还要多久
地址是公网还是私网IP 地址查询私有地址从公网连不通
端口该不该放行端口大全三段端口范围权限不同
服务端到底回了什么码HTTP 状态码403 与 404 指向不同原因

顺序建议:先确认协议(wss?)→ 再确认路径与代理 → 然后 Origin → 最后证书与网络。 前两步不需要碰服务端代码,排查成本最低。

#常见问题

#本地能连,部署到线上就连不上?

最常见的是混合内容:线上页面是 https,代码里还在连 ws://。其次是代理没转发 Upgrade 头 —— 本地直连后端没有代理这一层,所以本地正常。这两条按顺序查,通常第一次就命中。

#握手返回 403,是权限问题吗?

在 WebSocket 场景里,403 更常见的原因是 Origin 被拒,而不是鉴权失败。看服务端日志里有没有提到 Origin 或握手拒绝;如果日志里完全没有记录,那说明请求根本没到应用层,问题在代理。

#连接一直停在「连接中」不动?

说明握手既没成功也没失败 —— 请求被中间设备静默丢弃了。常见于企业防火墙、某些代理或不支持 WebSocket 的 CDN。先确认链路上有没有这类设备,再考虑换网络环境测试。

#需要带 token 才能连,能用网页工具测吗?

不能。浏览器提供的 WebSocket API 无法设置自定义请求头,所以 Authorization 加不上。可行的做法是用 Cookie 鉴权(同源时浏览器会自动带上),或者用 Postman、代码里的客户端测试。

#为什么收到的消息是乱码?

这个工具只处理文本帧,二进制帧不会按协议解析。如果服务端发的是二进制数据(图片分片、protobuf、压缩后的 JSON),需要按协议自己解。另外中文乱码要先确认服务端是不是按 UTF-8 发送的。

本文提到的工具

相关文章