Docker Compose部署Django Channels时Redis异常WebSocket连接失败
Django Channels Docker部署后WebSocket返回404修复指南
核心问题根因
- 当前web服务启动命令使用Gunicorn加载
core.wsgi:applicationWSGI应用,WSGI协议本身不支持WebSocket长连接,也不会加载Django Channels配置的ASGI WebSocket路由,所有WebSocket请求走到WSGI层找不到对应HTTP路由时会直接返回404。 - 本地执行
python manage.py runserver时WebSocket可正常使用,是因为Django开发服务器自动识别Channels配置后,会同时挂载WSGI/ASGI应用、自动分流HTTP和WebSocket请求,该逻辑和生产环境手动启动服务的逻辑不一致,不能直接复用判断标准。 - 日志中出现的sync worker超时重启现象,是因为WebSocket长连接请求打到仅支持同步HTTP的Gunicorn sync worker上,连接长期占用worker不释放触发了Gunicorn的超时熔断机制。
分步修复操作
1. 替换Web服务启动栈
Gunicorn默认仅支持WSGI协议,无法直接处理WebSocket请求,二选一调整启动方式即可:
- 方案一(Channels官方推荐):使用Daphne(Channels官方维护的ASGI服务器)托管全量服务,自动完成HTTP、WebSocket请求分流,无需单独部署Gunicorn。修改docker-compose.yml中web服务的启动命令为:
bash -c "daphne -b 0.0.0.0 -p 8000 core.asgi:application"
提前确认requirements.txt中已包含daphne依赖,正常安装Channels时会自动安装该依赖,若缺失补充daphne>=3.0即可。
- 方案二(需保留Gunicorn时选择):将Gunicorn的worker替换为Uvicorn的ASGI worker,直接加载ASGI应用,启动命令修改为:
bash -c "gunicorn core.asgi:application --worker-class uvicorn.workers.UvicornWorker --bind 0.0.0.0:8000"
该方案需要额外在requirements.txt中添加uvicorn[standard]依赖。
2. 校验Django配置项
- 检查settings.py中
INSTALLED_APPS配置,必须将daphne放在列表最顶部(优先级高于Django自带app、业务app),否则Channels路由加载优先级不足会导致路由不生效,参考配置:
INSTALLED_APPS = [ "daphne", "django.contrib.admin", "django.contrib.auth", # 其余Django自带app、业务app "channels", ]
- 确认settings.py中已显式指定ASGI应用路径:
ASGI_APPLICATION = "core.asgi.application"
- 现有CHANNEL_LAYERS配置中Redis地址写为服务名
("redis", 6379)是正确配置,同Docker自定义网络下可直接通过服务名解析通信,无需改回0.0.0.0。
3. 容器配置修正
- 之前尝试在8001端口启动Daphne仍无法连接时,优先检查两点:一是docker-compose.yml中是否将8001端口映射到宿主机;二是前端WebSocket请求的端口是否和Daphne监听端口一致,不要将WebSocket请求打到仅跑WSGI服务的8000端口。
- Redis无需额外做网络关联配置,只要web、redis、db三个服务同属
app_network网络,entrypoint中netcat连通性检测通过就说明网络链路正常。 - 重新构建镜像时添加
--no-cache参数,避免旧镜像缓存的启动命令、配置未生效:
docker-compose down docker-compose up -d --build --no-cache
有效性验证
- 部署完成后进入web容器内部,执行
curl http://127.0.0.1:8000/ws/accueil/accueil/,如果返回WebSocket握手相关响应而非404页面,说明ASGI服务已正常加载路由。 - 查看web容器运行日志,启动成功后会显示Daphne/Uvicorn的启动标识,不会再出现Gunicorn sync worker超时重启的报错。
- 前端测试连接时,未配置SSL的场景下使用
ws://<服务器IP>:8000/ws/xxx/格式的地址,不要误用wss协议。
内容的提问来源于stack exchange,提问作者Ramon G.
相关产品推荐
相关产品推荐

