Django用ASGI跑不起来WebSocket是因为默认runserver是WSGI模式,不处理WebSocket;需Django 3.1+、ASGI配置(asgi.py中ProtocolTypeRouter)、channels中间层及正确路由,缺一不可。

为什么Django用ASGI跑不起来WebSocket
因为默认的runserver是WSGI模式,压根不处理WebSocket连接——它连websocket.connect事件都收不到。ASGI不是换个命令就行,得换服务器、改配置、还要确认Django版本支持。
- Django 3.1+ 才原生支持ASGI应用入口(
asgi.py),老版本得靠django-channels兜底 -
channels不是可选插件,是WebSocket的必需中间层:Django本身不解析ws://协议,全靠它把ASGI消息路由到consumer - 即使用了Uvicorn,如果没装
channels或没在INSTALLED_APPS里加channels,请求直接404,连错误日志都不报
Daphne和Uvicorn选哪个跑ASGI
Uvicorn更快,但Daphne对Channels更“懂行”——尤其在多进程、连接复用、HTTP/2支持上,Daphne是Channels官方推荐的。
-
uvicorn启动时必须显式指定--factory或加载asgi:application,漏掉asgi.py路径就报AssertionError: No application configured -
daphne默认就认asgi.py,但要求channels版本匹配:Django 4.2建议用channels>=4.0.0,低版本会卡在get_channel_layer()初始化失败 - 本地开发用
uvicorn asgi:application --reload最顺;上生产别只图快,daphne -b 0.0.0.0:8000 myproject.asgi:application更稳,尤其有长连接场景
ASGI配置里最容易漏的三件事
不是写了asgi.py就能跑,Django的ASGI支持是分层激活的:设置、路由、消费者,缺一层WebSocket就静默失败。
-
settings.py里必须有ASGI_APPLICATION = "myproject.asgi.application",拼错app名或路径,Uvicorn启动成功但所有WebSocket请求返回500 -
asgi.py里不能只写application = get_asgi_application(),得套一层ProtocolTypeRouter,否则HTTP能通,WS直接被忽略 -
routing.py里WebSocket路由必须用URLRouter包着,写成URLPattern格式(比如re_path(r"^ws/", ...)),正则末尾少个$会导致路由错配,连接建立后立刻断开
怎么验证WebSocket真连上了
别只看浏览器控制台没报错,得抓底层行为:连接是否进consumer、channel layer有没有发消息、连接是否被ASGI服务器中途切断。
- 在consumer的
connect(self)里加print("WS connected"),启动时用uvicorn --log-level debug,看到connected to client才算真通 - 用
redis-cli monitor(如果channel layer是Redis)看有没有PUBLISH动作,没有说明消息根本没进channel layer - 浏览器用
new WebSocket("ws://localhost:8000/ws/")测试时,如果onopen触发但onmessage永远不触发,大概率是consumer里漏了self.accept()——这是最常被忽略的一行
异步Consumer里self.accept()必须是awaitable,写成self.accept()不加await,连接就卡在pending状态,浏览器看起来像“已连接”实则不可用。










