You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Nginx+uWSGI+Django环境WebSocket请求404问题排查求助

排查Nginx+uWSGI+Django环境下WebSocket 404错误的核心要点

从你的描述来看,问题大概率出在组件配置冲突、Nginx转发规则缺失或者Django WebSocket路由实现不匹配这几个方面,咱们一步步拆解:

1. 先理清:你混用了两种不兼容的Django WebSocket实现

你的配置里同时出现了两个完全独立的WebSocket方案,这是核心矛盾:

  • uwsgi.ini中配置了WEBSOCKET_FACTORY_CLASS="dwebsocket.backends.uwsgi.factory.uWsgiWebSocketFactory"(属于dwebsocket库的配置)
  • Django settings里又用了ProtocolTypeRouter({'websocket':AuthMiddlewareStack(URLRouter(alarm.routing.channel_routing))})(属于Django Channels的配置)

这两个库的路由机制完全不同,同时启用会导致WebSocket请求找不到对应的处理逻辑,直接返回404。你必须二选一:

  • 若继续用dwebsocket:删掉Channels相关的ProtocolTypeRouter配置,改用dwebsocket的路由方式(比如在urls.py里给/alarm配置带@require_websocket装饰器的视图)
  • 若使用Channels:删掉uwsgi.ini里的dwebsocket工厂类配置,改用Channels推荐的部署方式(比如用daphne作为WebSocket入口,或配置uWSGI支持Channels的ASGI协议)

2. 修正uWSGI的启动参数与配置匹配性

你当前的启动命令uwsgi --init uwsgi.ini --http_websockets和配置存在冲突:

  • http = :8008是让uWSGI直接作为HTTP服务器监听8008端口,--http_websockets是给这个模式开启WebSocket支持的
  • socket = :10002是让uWSGI通过TCP socket和Nginx通信,这个模式下需要用--websockets参数(而非--http_websockets)开启WebSocket支持

因为你的Nginx是监听10001并转发到uWSGI的10002端口,正确做法是:

  • 删掉uwsgi.ini里的http = :8008(不需要uWSGI直接对外提供HTTP服务)
  • 启动命令改为uwsgi --ini uwsgi.ini --websockets(给socket模式开启WebSocket支持)

3. 补全Nginx的WebSocket转发规则

即使uWSGI配置正确,Nginx如果没处理好WebSocket的握手请求,也会导致失败。针对/alarm路径,你的Nginx location配置必须包含WebSocket相关头转发:

server {
    listen 10001;
    server_name your_host;

    # 处理HTTP请求(比如/events路径)
    location /events {
        include uwsgi_params;
        uwsgi_pass 127.0.0.1:10002;
    }

    # 处理WebSocket请求(/alarm路径)
    location /alarm {
        include uwsgi_params;
        uwsgi_pass 127.0.0.1:10002;
        # 必须添加这两个头支持WebSocket握手
        uwsgi_param UWSGI_SCHEME $scheme;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "upgrade";
    }
}

注意:使用uwsgi_pass时,要确保uWSGI的uwsgi_params文件包含必要头,同时添加UWSGI_SCHEME让uWSGI识别请求类型。

4. 验证Django路由的正确性

若选择dwebsocket方案

在urls.py里明确配置/alarm的WebSocket视图:

from django.urls import path
from . import views

urlpatterns = [
    path('events/', views.events_view),
    path('alarm/', views.alarm_websocket_view),
]

对应的视图使用dwebsocket装饰器:

from dwebsocket.decorators import require_websocket

@require_websocket
def alarm_websocket_view(request):
    # 处理WebSocket逻辑示例
    while True:
        message = request.websocket.wait()
        if message is None:
            break
        request.websocket.send(message)

若选择Channels方案

确保alarm.routing.channel_routing正确映射/alarm路径到消费者:

# alarm/routing.py
from django.urls import re_path
from . import consumers

websocket_urlpatterns = [
    re_path(r'^alarm/$', consumers.AlarmConsumer.as_asgi()),
]

在settings.py里指定ASGI应用入口:

ASGI_APPLICATION = 'your_project.asgi.application'

同时在uwsgi.ini里添加ASGI支持配置:

asgi = your_project.asgi:application
http-websockets = true

最后一步:重启服务测试

修改配置后按顺序重启:

  1. 停止uWSGI进程:uwsgi --stop uwsgi.pid(若配置了pid文件)
  2. 重启Nginx:nginx -s reload
  3. 重新启动uWSGI:uwsgi --ini uwsgi.ini --websockets(对应dwebsocket)或uwsgi --ini uwsgi.ini(对应Channels)

再用ws.create_connection("ws://127.0.0.1:10001/alarm")测试,应该就能正常握手了。

内容的提问来源于stack exchange,提问作者LittleCabbage

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.13 07:31:26