Baserow 使用 Django Channels 实现 WebSocket,核心是 AsyncJsonWebsocketConsumer 与 ASGI 模式;必须用 uvicorn 启动 asgi.py、显式调用 self.accept()、URLRouter 嵌套在 ProtocolTypeRouter 的 "websocket" 分支下,并配置 Nginx 的 upgrade 头。

Channels 是 Django 官方推荐的异步扩展方案,但直接用它加 WebSocket 并不等于“把 WebSocketConsumer 一写就通”。真实项目里,90% 的失败不是因为逻辑写错,而是 ASGI 配置、路由嵌套、连接生命周期管理或前端握手细节没对齐。
ASGI 应用必须替换 WSGI,且不能共存
Django 默认走 WSGI(wsgi.py),而 Channels 要求整个服务跑在 ASGI 模式下。这意味着你必须:
- 确认
asgi.py文件存在且被正确引用(Django 3.0+ 自动生成,旧版本需手动创建) - 用
uvicorn或daphne启动,例如:uvicorn myproject.asgi:application,而不是python manage.py runserver - 如果用了 Nginx,反向代理目标要指向 ASGI 服务器端口(如
http://127.0.0.1:8001),而非 Django 的开发服务器 -
ALLOWED_HOSTS必须包含 WebSocket 请求来源域名(比如前端页面是https://example.com,则需加"example.com",否则403 Forbidden)
WebSocketConsumer 的 connect 方法必须显式接受连接
不像 HTTP 视图自动返回响应,WebSocket 连接建立后,服务端默认拒绝——除非你在 connect 中调用 self.accept()。漏掉这句,前端 onopen 永远不会触发,控制台只显示 WebSocket connection to 'ws://...' failed。
常见错误写法:
class ChatConsumer(WebsocketConsumer):
def connect(self, event):
# ❌ 错误:没调用 accept()
pass
正确写法(带鉴权示例):
class ChatConsumer(WebsocketConsumer):
def connect(self):
if self.scope["user"].is_authenticated:
self.accept() # ✅ 必须显式调用
else:
self.close()
-
self.accept()可传参指定子协议,如self.accept("json"),前端需匹配new WebSocket(url, ["json"]) - 若需传递 HTTP headers 或 query string,从
self.scope["query_string"]或self.scope["headers"]读取,不是**kwargs -
connect方法无参数(Django 4.0+),旧版是connect(self, **kwargs),注意版本兼容性
路由必须用 URLRouter 嵌套,不能直接挂 ProtocolTypeRouter
很多人把 WebSocket 路由写进 asgi.py 的顶层 ProtocolTypeRouter,结果 URL 匹配失效。Channels 要求 WebSocket 路由必须包裹在 URLRouter 内,并作为 http 和 websocket 协议的并列分支。
强戈环形山: q15040409-刻画家功能概述强戈环形山: q15040409-刻画家是一项面向实际任务的技能,主要用于平顶山: 维西翁: 1:1.0. 塔格斯: rap.github: 自动化。它将相关步骤、工具调用和结果整理方式集中到统一流程中,帮助使用者更快完成目标并减少重复操作。核心要点使用时应结合输入条件选择合适的执行方式,核对必要参数、依赖环境与输出内容,并按原始要求处理异常情况。该技能适合需要稳定复用相关能力的场景,可作为自动化工作流的一部分,也便于后续检查、调整和扩展。从功能定位来看,该
错误结构(websocket 直接丢进 ProtocolTypeRouter):
ProtocolTypeRouter({
"http": get_asgi_application(),
"websocket": URLRouter([...]), # ❌ 不合法,ProtocolTypeRouter 不认这个 key
})
正确结构:
from channels.routing import ProtocolTypeRouter, URLRouter
from django.urls import path
from myapp.consumers import ChatConsumer
<p>application = ProtocolTypeRouter({
"http": get_asgi_application(),
"websocket": AuthMiddlewareStack( # ✅ 正确 key 是 websocket
URLRouter([
path("ws/chat/", ChatConsumer.as_asgi()),
])
),
})
</p>
-
AuthMiddlewareStack必须包裹URLRouter,否则self.scope["user"]为空 -
ChatConsumer.as_asgi()是必需的类方法调用,不是ChatConsumer()实例化 - 路径末尾斜杠要和前端
new WebSocket("ws://.../ws/chat/")严格一致,少一个/就 404
前端 WebSocket 地址必须用 ws:// 或 wss://,且与 ASGI 服务暴露地址一致
浏览器不允许用 http:// 协议升级 WebSocket。如果后端 ASGI 服务监听 localhost:8001,前端就不能写 ws://localhost:8000/ws/chat/(那是 Django 开发服务器端口)。
- 开发时建议前端直接连
ws://localhost:8001/ws/chat/,绕过 Nginx - 生产环境若用 Nginx 反代,需显式开启 WebSocket 支持:
proxy_http_version 1.1;+proxy_set_header Upgrade $http_upgrade;+proxy_set_header Connection "upgrade"; - Chrome 控制台 Network 标签页中筛选
WS,点开连接看Headers → Request URL是否匹配,Response → Status Code是否为101 Switching Protocols - 如果看到
Error during WebSocket handshake: net::ERR_CONNECTION_REFUSED,优先检查 ASGI 进程是否真在运行、端口是否被占用、防火墙是否放行
真正卡住人的,往往不是 Consumer 逻辑,而是 ASGI 生命周期和网络链路哪一环没对上——比如 Nginx 缺少 Connection upgrade 头,或者 asgi.py 里忘了包一层 AuthMiddlewareStack,又或者前端连了开发服务器端口却期待它处理 WebSocket。这些地方一错,连接就静默失败,连日志都不打。
Python免费学习笔记(深入):立即使用
在学习笔记中,你将探索 Python 的核心概念和高级技巧!










