Nginx反向代理后Daphne协议升级始终路由至HTTP而非WebSocket
解决Nginx反向代理下Django Channels WebSocket被错误路由的问题
看起来你遇到的核心问题是Nginx没有正确区分WebSocket握手请求和普通HTTP请求,导致WebSocket连接被误转发给了不处理WebSocket的uWSGI。本地环境正常是因为Daphne直接处理了所有请求(包括HTTP和WebSocket),但部署后拆分了uWSGI和Daphne,就需要Nginx做正确的路由转发。下面是一步步的解决方案:
关键配置要点
Nginx需要识别WebSocket的握手特征:请求头里的Upgrade: websocket和Connection: upgrade,并将这类请求转发给Daphne,而普通HTTP请求转发给uWSGI。
完整的Nginx配置示例
假设你的Daphne服务监听127.0.0.1:8000,uWSGI通过unix套接字/path/to/your/project.sock通信,WebSocket请求路径以/ws/开头,配置如下:
server { listen 80; server_name your-domain.com; # 替换成你的域名 # 处理普通HTTP请求,转发给uWSGI location / { uwsgi_pass unix:/path/to/your/project.sock; # 或者用uwsgi://127.0.0.1:8001(如果uWSGI监听端口) include uwsgi_params; # 传递必要的请求头,确保Django能正确获取客户端信息 uwsgi_param Host $host; uwsgi_param X-Real-IP $remote_addr; uwsgi_param X-Forwarded-For $proxy_add_x_forwarded_for; uwsgi_param X-Forwarded-Proto $scheme; } # 专门处理WebSocket请求,转发给Daphne location /ws/ { proxy_pass http://127.0.0.1:8000; # Daphne的监听地址 proxy_http_version 1.1; # WebSocket需要HTTP/1.1支持 # 必须设置的WebSocket握手头 proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection "upgrade"; # 同样传递客户端信息头 proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto $scheme; # 可选但推荐:设置长连接超时,避免WebSocket被Nginx过早断开 proxy_connect_timeout 7d; proxy_send_timeout 7d; proxy_read_timeout 7d; } }
部署注意事项
- 独立运行Daphne:确保Daphne是单独启动的服务(比如用systemd管理),而不是和uWSGI共用端口。例如systemd服务配置:
[Unit] Description=Daphne service for Django Channels After=network.target [Service] User=your-user WorkingDirectory=/path/to/your/project ExecStart=/path/to/venv/bin/daphne -b 127.0.0.1 -p 8000 yourproject.asgi:application Restart=always [Install] WantedBy=multi-user.target - 匹配WebSocket路径:确保前端请求的WebSocket路径(比如
ws://your-domain.com/ws/notifications/)和Nginx的location /ws/规则匹配。如果你的WebSocket路径不同,要调整Nginx的location规则。 - 重启服务:修改Nginx配置后执行
sudo systemctl restart nginx,并确保Daphne和uWSGI服务都正常运行。
验证与排查
- 检查WebSocket握手:用浏览器开发者工具打开Network面板,筛选WebSocket请求,查看响应状态码是否为
101 Switching Protocols,请求头里的Upgrade和Connection是否被正确传递。 - 测试握手命令:用curl手动测试WebSocket握手:
如果返回curl -i -N -H "Connection: Upgrade" -H "Upgrade: websocket" -H "Host: your-domain.com" -H "Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==" -H "Sec-WebSocket-Version: 13" http://your-domain.com/ws/HTTP/1.1 101 Switching Protocols,说明握手成功。 - 查看日志:如果还是失败,检查Nginx的错误日志(通常在
/var/log/nginx/error.log)和Daphne的日志,看是否有连接被拒绝或路由错误的信息。
内容的提问来源于stack exchange,提问作者Jagadesh Babu T
相关产品推荐
相关产品推荐

