WebSocket握手慢主因是Nginx配置未正确透传Upgrade和Connection头、超时设置过短或缓冲机制干扰;需在location块中精准配置proxy_http_version 1.1、proxy_set_header Upgrade $http_upgrade、proxy_set_header Connection "upgrade",并调大超时、关闭缓冲与缓存。

WebSocket 握手慢,八成不是代码问题,而是 Nginx 配置没“听懂”客户端的升级请求。真正卡点往往在协议头透传不全、超时设置过短、缓冲机制干扰,或系统资源未跟上。优化目标很明确:让 101 Switching Protocols 响应在毫秒级返回,不被代理层拦腰截断。
确保 Upgrade 和 Connection 头精准透传
这是握手成功的前提。Nginx 默认会过滤掉非标准头,而 Upgrade: websocket 和 Connection: Upgrade 是 WebSocket 协议识别的唯一钥匙:
- 必须写在
location块内,不能只放在 upstream 或 http 全局块中 -
proxy_http_version 1.1;—— HTTP/1.0 不支持协议升级,强制设为 1.1 -
proxy_set_header Upgrade $http_upgrade;—— 注意是$http_upgrade变量,不是固定字符串"websocket" -
proxy_set_header Connection "upgrade";—— 引号不可省,值必须是"upgrade"(小写),不能是空字符串或"" - 漏掉任意一项,浏览器 Network 面板里看到的响应状态码就是
200 OK,而非101 Switching Protocols
调大超时并关闭干扰机制
WebSocket 是长连接,但 Nginx 默认按 HTTP 短连接逻辑处理。若沿用默认配置,空闲几秒就断开,或响应稍慢就被判超时:
-
proxy_read_timeout 86400;—— 设为 24 小时(或略大于客户端心跳间隔),防止空闲连接被静默关闭 -
proxy_send_timeout 86400;—— 避免服务端分片推送大消息时中途断连 -
proxy_buffering off;—— 关闭响应缓冲,否则消息堆积延迟,实时性丧失 -
proxy_cache off;—— 显式禁用缓存,避免 Upgrade 请求被缓存命中返回 200 - 不要设
proxy_connect_timeout过小(如 3 秒),后端启动或鉴权稍慢就会直接失败
精简握手阶段服务端逻辑
Nginx 转发快,但若后端在握手时做同步阻塞操作,整体耗时仍会飙升:
- 避免在握手回调中执行数据库查询、远程 HTTP 调用或 JWT 全量解析
- 鉴权尽量轻量化:用 Redis 缓存 token 状态,或仅校验签名有效性,把完整权限检查延后到首次业务消息到达时
- Sec-WebSocket-Key 的 SHA-1 + Base64 计算应走原生库(如 Python 的
hashlib.sha1()),避免正则、多次字符串切片等低效操作 - 使用异步框架(如 FastAPI + websockets、Node.js ws、Swoole)替代同步模型(如 Flask 默认模式),防止单个握手阻塞整个 worker
排查 DNS 与系统级瓶颈
有时问题不在 Nginx 配置本身,而在底层环境拖慢握手起始环节:
- 检查服务器
/etc/resolv.conf或网卡配置(如/etc/sysconfig/network-scripts/ifcfg-ens32)中的 DNS 是否可达;nslookup 域名卡顿 60 秒,大概率是 DNS 解析阻塞 - 增大系统文件描述符上限:
echo '* soft nofile 1048576' >> /etc/security/limits.conf,并确认 Nginx 启动用户已生效 - 优化内核参数:
net.core.somaxconn = 65535、net.ipv4.tcp_tw_reuse = 1,缓解 TIME_WAIT 泛滥和连接队列溢出 - 用 curl 手动模拟握手:
curl -i -H "Upgrade: websocket" -H "Connection: Upgrade" https://your-domain.com/ws,观察是否返回 101 及对应头字段



















