Django本身不支持WebSocket,必须使用ASGI服务器(如Daphne、Uvicorn)和Channels库协同工作;仅安装Channels无效,因其仅为协议抽象层,依赖ASGI服务器接收并分发WebSocket握手请求,而默认runserver是WSGI服务器,无法识别websocket事件。

Django 本身不支持 WebSocket,必须借助 ASGI 服务器和第三方库(如 daphne + channels)才能实现;直接用 runserver 启动的 WSGI 模式完全无法处理 WebSocket 连接。
为什么不能只装 channels 就行?
因为 channels 是协议抽象层,它依赖底层 ASGI 服务器来真正接收和分发 WebSocket 握手请求。Django 默认的 runserver 是 WSGI 服务器,根本不认识 websocket.connect 这类事件。
- 必须用
daphne、uvicorn或hypercorn这类 ASGI 服务器启动项目 -
ASGI_APPLICATION设置必须指向routing.py中的application对象,不是WSGI_APPLICATION -
channels的消费者(Consumer)代码写在consumers.py,但不会被 WSGI 自动加载
如何配置 channels 并让 WebSocket 路由生效?
关键在三处:安装、路由注册、ASGI 入口。漏掉任一环节都会导致连接被 404 或直接拒绝。
- 安装:
pip install channels daphne(daphne是 Django 官方推荐的 ASGI 服务器) - 在
settings.py中添加'channels'到INSTALLED_APPS,并设置ASGI_APPLICATION = 'myproject.asgi.application' - 创建
asgi.py(Django 3.0+ 自动生成),确保它用ProtocolTypeRouter包裹了URLRouter,且 WebSocket 路由指向你的routing.py -
routing.py中用URLRouter+re_path映射路径到消费者,例如:re_path(r'ws/chat/(?P<room_name>\w+)/$', ChatConsumer.as_asgi())</room_name>
WebSocket 消费者里怎么收发消息?要注意什么?
AsyncWebsocketConsumer 是最常用基类,所有方法都是异步的,不能混用 time.sleep() 或同步数据库操作。
立即学习“Python免费学习笔记(深入)”;
-
connect()中必须调用self.accept(),否则连接会被立即关闭(浏览器看到WebSocket is closed before the connection is established) - 发送消息统一用
await self.send(text_data=json.dumps(...)),不是self.channel_layer.group_send() - 广播给组内所有人要用
self.channel_layer.group_add()+group_send(),且组名不能含空格或特殊字符(建议用slugify(room_name)处理) - 断开时记得
group_discard,否则残留组成员会导致内存泄漏或重复推送
前端如何正确连接并避免常见报错?
URL 必须和后端路由严格匹配,且协议要对应 ASGI 服务监听的地址(开发环境通常是 ws://127.0.0.1:8000/ws/...,不是 http)。
- 如果看到
Failed to construct 'WebSocket': The URL 'http://...' is invalid,说明用了http协议——改用ws://(开发)或wss://(生产) - 连接后立刻收到
onerror或直接onclose,先检查 Django 日志里有没有WebSocket HANDSHAKE FAILED,大概率是路由没匹配上或connect()里没accept() - 用
new WebSocket(url)后,必须等onopen触发再调用send(),否则会报InvalidStateError: Failed to execute 'send' on 'WebSocket': Still in CONNECTING state
最容易被忽略的是:ASGI 服务器启动命令不是 python manage.py runserver,而是 daphne myproject.asgi:application --port 8000 --bind 127.0.0.1:8000(或 uvicorn myproject.asgi:application --port 8000)。少这一步,所有后端逻辑都只是“纸上谈兵”。


















