Appearance
前言
在本地开发 Web 应用时,经常会遇到 WebSocket (ws / wss) 连接失败的问题,比如浏览器控制台显示 “Pending” 或 “Error 1006”。 本文整理了常见原因、调试工具、协议关系,以及证书在其中的作用,帮助你快速定位和解决问题。
协议关系总览
HTTP 与 WebSocket
- HTTP:基于请求-响应模型,短连接。
- WebSocket:基于 TCP 的全双工长连接,通常通过 HTTP Upgrade 握手建立。
明文 vs 加密
ws://—— 明文 WebSocket,基于 TCP/80。wss://—— 加密 WebSocket,基于 TLS/443,相当于https://。
混合内容限制
- HTTPS 页面 → 只能连 wss://,不能连 ws://(被浏览器拦截)。
- HTTP 页面 → 可以连 ws:// 也可以连 wss://。
⚠️ 本地常见问题:
http://localhost:3000去连wss://example.com是允许的,但https://example.com去连ws://localhost:3000会被拦截。
证书在其中的作用
TLS 证书校验流程
浏览器发起 TLS 握手,带上
SNI(Server Name Indication)。服务器返回证书。
浏览器校验证书链:
- 域名是否包含在证书的 Subject Alternative Name (SAN)。
- 证书是否过期。
- 证书是否由受信任 CA 签发。
- 链是否完整(是否缺中间证书)。
常见报错
Hostname/IP does not match certificate's altnames→ 证书里没有目标域名。NET::ERR_CERT_AUTHORITY_INVALID→ 自签证书未被信任。NET::ERR_CERT_DATE_INVALID→ 证书过期或本地时间不对。526 Invalid SSL certificate(Cloudflare) → 源站证书有问题。
WebSocket 连接失败的常见原因
证书域名不匹配(最常见)。
- 例如访问
wss://test.example.com,但证书只包含www.example.com。
- 例如访问
Origin 白名单未放行。
- 服务端拦截了来自
http://localhost:3000的请求。
- 服务端拦截了来自
Nginx/CDN 未配置 WS 升级。
- 缺少
Upgrade、Connection头,握手失败。
- 缺少
网络代理/防火墙拦截。
- 公司网络或系统代理阻断了 wss 流量。
JWT/鉴权失败。
- token 过期或签发时间与服务器时间偏差大。
Nginx WebSocket 必备配置
nginx
# 复杂逻辑:升级头透传
map $http_upgrade $connection_upgrade {
default upgrade;
'' close;
}
server {
listen 443 ssl http2;
server_name example.com;
ssl_certificate /etc/nginx/ssl/example.com/fullchain.pem;
ssl_certificate_key /etc/nginx/ssl/example.com/privkey.pem;
location /ws/ {
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection $connection_upgrade;
proxy_set_header Host $host;
proxy_read_timeout 300s;
proxy_pass http://your_ws_upstream;
}
}测试 WebSocket 的常用工具
1. wscat(最常用)
安装:
npm install -g wscat使用:
bashwscat -c "wss://example.com/ws?token=xxx"功能:交互式 CLI,可以手动发消息、收消息。
2. websocat
安装:
brew install websocat(macOS) 或下载二进制。使用:
bashwebsocat wss://example.com/ws特点:更轻量,支持管道操作,可以脚本化测试。
3. curl(只能测试握手)
用于确认
101 Switching Protocols:bashcurl -i -N -H "Connection: Upgrade" -H "Upgrade: websocket" \ -H "Host: example.com" -H "Origin: http://localhost:3000" \ https://example.com/ws缺点:不能维持 WebSocket 会话。
4. 浏览器 DevTools
在 Network → WS 里查看:
101 Switching Protocols是否成功。Close Code是否 1006/1008。Security看证书是否正常。
快速排查步骤
浏览器 Network:看是否
101握手成功。命令行 wscat:排除前端代码影响。
OpenSSL:检查证书链。
bashopenssl s_client -connect example.com:443 -servername example.com </dev/null 2>/dev/null | openssl x509 -noout -subject -issuer -dates服务端日志:看握手是否被拒绝(403/400/404)。
总结
- 本地 http 页面连远端 wss 是允许的,问题大多出在证书或服务端配置。
- 证书必须包含访问的域名,否则浏览器直接拒绝。
- 推荐用 wscat/websocat 先测通道,再结合 DevTools 和 OpenSSL 确认问题。
- 若前面有 Nginx/CDN,一定要加上
Upgrade/Connection头。
要不要我再写一篇 “证书校验与 SAN 配置专门篇”,里面详细讲 多域名证书、泛域名证书、SNI 配置 这些实战?