Nginx代理WebSocket
Nginx代理WebSocket
引言
聊天、实时推送、在线协作这类场景用WebSocket长连接。前端经过Nginx访问后端WS服务时,如果只按普通HTTP反代配置,握手会失败,因为WebSocket要先发起Upgrade协议升级,Nginx必须把升级头透传给后端。
WebSocket握手原理
客户端先发HTTP请求,带Upgrade: websocket和Connection: Upgrade头,后端同意后把HTTP协议升级成持久双向长连接。Nginx默认不透传这两个头,导致握手400。
标准代理配置
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_set_header Host $host;
proxy_read_timeout 3600s;
}
- proxy_http_version 1.1:WS基于HTTP/1.1;
- Upgrade $http_upgrade:透传客户端升级协议;
- Connection "upgrade":标记连接升级;
- read_timeout拉长:长连接默认60秒无数据会被Nginx断开。
用map统一处理
不同location可能同时有HTTP和WS,写map避免硬编码:
map $http_upgrade $connection_upgrade {
default upgrade;
'' close;
}
# location内
proxy_set_header Connection $connection_upgrade;
普通HTTP请求$http_upgrade为空时走close,WS请求走upgrade,一套配置兼容。
常见问题
- 握手400/502:没加Upgrade和Connection头;
- 连接几十秒自动断开:read_timeout太短,按需拉长或服务端发心跳;
- wss(HTTPS)走Nginx终止TLS后,后端用ws即可;
- 后端端口和proxy_pass写对,别漏http://。
注意事项
- 长连接超时靠心跳和read_timeout共同维持;
- 集群WS要配合粘性会话或后端共享状态,否则消息发不到正确连接;
- HTTPS页面必须用wss://,浏览器会拦截混合内容;
- 改配置nginx -t后reload。
总结
Nginx代理WebSocket核心是加proxy_http_version 1.1、透传Upgrade和Connection头、拉长read_timeout,用map兼容普通HTTP。握手失败先查这三个头,断线先查超时和心跳。