后端WebSocket异步编程【免费下载链接】channelsDeveloper-friendly asynchrony for Django项目地址https://gitcode.com/gh_mirrors/ch/channels点击查看免费下载Channels 2.0.1 是 Channels 2.0 系列的首个补丁版本在保持 2.0 大版本重写成果的基础上为 WebSocket 场景补充了原生异步通用消费者将残缺的allowed_hosts_only装饰器替换为完整可用的 Origin 校验中间件并修复了URLRouter在多个路由场景下无法越过首个 URL 继续匹配的缺陷。本文以官方发布说明为骨架结合仓库源码与测试用例逐一拆解这三项变更的用法、原理与升级注意点帮助读者安全升级并正确使用异步 WebSocket 消费者与 Origin 校验能力。版本定位与升级须知Channels 2.0.1 是一个patch 级别的发布发布说明原文其定位是在 2.0.0 的大规模重构由 Channels 1 的消息通过 channel layer 传输改为应用直接运行在协议服务器内部并全面转向 asyncio 异步运行时详见 2.0.0 发布说明基础上补充少量小特性并修复一个 URL 解析缺陷。升级时有一个官方反复强调的注意点更新 Channels 的同时务必同步升级其依赖asgiref与daphne。因为这两个包各自也会发布自己的 bugfix 更新而部分表面上看像 Channels 自身问题的 bug实际根源在 asgiref 或 daphne 中。仅单独升级 Channels 而保留旧版依赖可能在运行时遇到难以定位的异常。本次 2.0.1 的向后不兼容变更为None即按官方说明从 2.0.0 升级到 2.0.1 不需要修改应用代码。新特性一原生异步 WebSocket 通用消费者2.0.1 为 WebSocket 场景引入了两个新的异步版本通用消费者channels.generic.websocket.AsyncWebsocketConsumerchannels.generic.websocket.AsyncJsonWebsocketConsumer它们与 2.0 已有的同步版WebsocketConsumer、JsonWebsocketConsumer在方法签名上一一对应但所有处理方法均为协程self.send等操作也全部变为可await的异步调用。相关背景与用法可参见 Consumers 文档。用法示例一个最基本的异步 WebSocket 消费者如下取自 Consumers 文档from channels.generic.websocket import AsyncWebsocketConsumer class MyConsumer(AsyncWebsocketConsumer): async def connect(self): # 连接建立时调用 # 接受连接 await self.accept() # 或接受连接并指定服务端选中的子协议 # 客户端声明的子协议列表位于 self.scope[subprotocols] await self.accept(subprotocol) # 拒绝连接 await self.close() async def receive(self, text_dataNone, bytes_dataNone): # 每个帧到达时调用text_data 与 bytes_data 二选一 # 发送文本帧 await self.send(text_dataHello world!) # 发送二进制帧 await self.send(bytes_dataHello world!) # 强制关闭连接 await self.close() # 或携带自定义 WebSocket 错误码 await self.close(code4123) async def disconnect(self, close_code): # 连接关闭时调用 passAsyncJsonWebsocketConsumer则自动完成 JSON 的编解码你只需实现receive_json(self, content)接收已解码的 JSON 对象用await self.send_json(content)发送数据框架会负责json.loads/json.dumps。若需自定义编解码逻辑可覆写encode_json与decode_json类方法——在异步版本中这两个方法同样是协程async def见 channels/generic/websocket.py。源码级流程拆解从 channels/generic/websocket.py 的AsyncWebsocketConsumer实现可以看到异步版本完整复刻了同步版的语义连接建立阶段协议服务器下发websocket.connect消息后框架调用websocket_connect其内部尝试调用用户实现的connect()若connect()抛出AcceptConnection则自动accept()抛出DenyConnection则自动close()异常定义见 channels/exceptions.py。帧收发阶段websocket_receive根据消息中text与bytes键区分文本帧与二进制帧分别以text_data/bytes_data关键字传入receive()send()则按传入内容构造{type: websocket.send, text: ...}或{type: websocket.send, bytes: ...}事件且支持closeTrue时发送后立即关闭连接。断开清理阶段websocket_disconnect在调用用户disconnect()后会执行await aclose_old_connections()来自 channels/db.py并抛出StopConsumer以干净地终止 ASGI 应用——这正是 Consumers 文档 中强调的关闭后必须抛出StopConsumer约定的内置实现避免应用因超时被 Daphne 强杀并产生警告。另外注意本版本中groups类属性默认初始化为空列表见 channels/generic/websocket.py而连接时自动加入 group、断开时自动退出的内置组管理是在后续 2.1.0 版本中引入的见 2.1.0 发布说明不属于 2.0.1 的能力范围。何时选择异步消费者官方在 Consumers 文档 中给出的选型建议是默认使用同步版SyncConsumer/WebsocketConsumer它们运行在线程池中可安全调用 Django ORM 等同步代码不会阻塞整个服务器事件循环仅在确定收益时使用异步版即你要处理的是可并行化的长耗时任务且只调用异步原生库例如用 HTTPX 并行拉取 20 个页面。若在AsyncConsumer中调用慢速同步函数会阻塞整个事件循环若确实需要从异步消费者中调用同步函数可使用asgiref.sync.sync_to_async调用 ORM 则应使用database_sync_to_async适配器或 ORM 的异步方法aget等。新特性二OriginValidator 与 AllowedHostsOriginValidator 中间件2.0.1 移除了在 2.0 中意外混入但实际不可用的allowed_hosts_only装饰器取而代之的是一组全新的ASGI 中间件channels.security.websocket.OriginValidatorchannels.security.websocket.AllowedHostsOriginValidator相关背景与用法详见 Security 文档。为什么要校验 OriginWebSocket 握手本身是一次 HTTP 请求会携带用户站点的 Cookie 与会话。这意味着任意第三方网站都可以向你的域名发起 WebSocket 连接并在连接中携带受害者浏览器里的 Cookie——存在跨站请求伪造CSRF风险。若你的 WebSocket 会下发私密数据就必须限制允许发起连接的站点。这就是 Origin 校验的用途检查握手请求的Origin头是否在白名单内。用法示例from channels.security.websocket import OriginValidator application ProtocolTypeRouter({ websocket: OriginValidator( AuthMiddlewareStack( URLRouter([ ... ]) ), [.goodsite.com, http://.goodsite.com:80, http://other.site.com], ), })白名单元素支持两种形态仅域名例如.allowed-domain.com点前缀表示该域名及其所有子域完整 Origin格式为scheme://domain[:port]例如http://allowed-domain.com:80。端口可省略但官方建议显式给出因为中间件会按 Origin 规范比对协议与端口。如果想放行任意来源可直接使用*。AllowedHostsOriginValidator直接复用 ALLOWED_HOSTS绝大多数情况下允许的域名集合与 Django 的ALLOWED_HOSTS设置一致后者本身对Host头做类似的安全校验。此时不必重复声明列表from channels.security.websocket import AllowedHostsOriginValidator application ProtocolTypeRouter({ websocket: AllowedHostsOriginValidator( AuthMiddlewareStack( URLRouter([ ... ]) ), ), })从 channels/security/websocket.py 的实现可以看到AllowedHostsOriginValidator是一个工厂函数它读取settings.ALLOWED_HOSTS构造OriginValidator并且在DEBUG模式且ALLOWED_HOSTS为空时自动放行localhost、127.0.0.1、[::1]这与 Django 自身的 Host 校验行为保持一致。匹配逻辑源码剖析OriginValidator是标准 ASGI 中间件async def __call__(self, scope, receive, send)整体流程见 channels/security/websocket.py校验scope[type] websocket非 WebSocket 连接直接抛ValueError从scope[headers]中查找borigin头并urlparse解析若校验通过把控制权交给被包裹的应用否则交给WebsocketDenier一个直接close()拒绝连接的内部消费者见同文件 channels/security/websocket.py。核心匹配逻辑match_allowed_originchannels/security/websocket.py值得注意的几点点前缀通配域名以.开头时通过 Django 的is_same_domain匹配该域名及其所有子域。注意*.example.com这种写法不再支持必须使用.example.com协议与端口比对get_origin_port会为http/ws补默认端口 80、为https/wss补默认端口 443channels/security/websocket.py因此http://allowed-domain.com与http://allowed-domain.com:80视为等价空 Origin 或非法 Origin 一律拒绝除非白名单含*。仓库的 tests/security/test_websocket.py 提供了完整的正反用例佐证上述行为例如[allowed-domain.com]拒绝来自http://bad-domain.com的连接[.allowed-domain.com]接受http://www.allowed-domain.com[*]时无头连接也放行空白名单与空 Origin 头、非法 Origin 头均被拒绝。提示域名字段格式在后续 2.1.0 中进一步规范化*.example.com彻底弃用统一用.example.com见 2.1.0 发布说明。本仓库源码与测试均已按.domain格式实现与验证。修复URLRouter 无法越过首个 URL 继续匹配的问题2.0.1 修复了URLRouter的一个解析缺陷在某些情况下路由无法匹配到列表中第一个 URL 之后的条目。修复的同时官方新增了一整套 URL 解析测试套件防止回归。源码中的修复痕迹从 channels/routing.py 的URLRouter实现可以看到其完整解析机制路由以 Django 的path()/re_path()对象为输入逐个与scope中的路径匹配最外层路由器会处理scope[root_path]如挂在反向代理子路径下时并剥掉路径开头的/与 Django URL 处理保持一致匹配成功后把剩余未匹配部分写入scope[path_remaining]把捕获的位置参数与关键字参数合并进scope[url_route]再调用目标应用——这正是嵌套路由及后续 2.1 的URLRouter嵌套复用得以实现的基础外层路由器未匹配时抛ValueError而path_remaining已存在即处于内层时抛Resolver404允许解析回退到外层继续尝试。需要留意的是在 2.0.1 版本中URLRouter之间的嵌套即外层剥掉匹配部分、内层只匹配剩余部分是下一个版本 2.1.0 引入的行为见 2.1.0 发布说明2.0.1 的修复聚焦于单个URLRouter内部多路由场景下首路由之外的路由无法命中这一缺陷。测试套件佐证仓库的 tests/test_routing.py 覆盖了丰富的解析场景可作为该 bug 已修复并防回归的证据test_url_router验证path()、path(foo/)、re_path(rbar)等基础匹配位置参数url_route[args]、关键字参数url_route[kwargs]、路由默认参数kwargs{default: 42}以及root_path处理test_url_router_path验证path()风格的路由与类型转换int:year得到整数 2012test_path_remaining验证内层路由器无匹配时解析会继续回退到外层路由器并命中后续路由——这正是越过首个 URL 继续匹配语义的回归保障test_invalid_routes确认在URLRouter中使用 Django 的include()会抛出ImproperlyConfiguredinclude() is not supported in URLRouter.引导用户改用嵌套URLRouter实例。升级建议与小结综合来看2.0.1 是一次小而稳的补丁发布升级动作可归纳为同步升级依赖将channels、asgiref、daphne三者的版本一并更新避免依赖不匹配导致的隐性 bug迁移 Origin 校验代码若你曾在 2.0 中尝试使用allowed_hosts_only装饰器请改用以OriginValidator/AllowedHostsOriginValidator包裹 WebSocket 应用的中间件写法示例见 Security 文档并确认白名单使用.domain点前缀格式验证 WebSocket 路由升级后运行仓库自带的 路由测试 思路重点回归多个路由并存、首个路由不命中时后续路由能否正确接管的场景新特性按需采用AsyncWebsocketConsumer与AsyncJsonWebsocketConsumer仅在确定受益于原生异步、且全部依赖为异步原生库时使用否则继续使用同步版消费者。至此读者应能完整理解 Channels 2.0.1 的三项核心变更——异步 WebSocket 消费者、Origin 校验中间件、URLRouter 解析修复——的用法、源码原理与升级路径并可直接对照 Consumers 文档、Security 文档 与 Routing 文档 继续深入实践。赞分享后端WebSocket异步编程【免费下载链接】channelsDeveloper-friendly asynchrony for Django项目地址https://gitcode.com/gh_mirrors/ch/channels点击查看免费下载相关推荐Arthas 4.3.1 发布详解WebSocket 心跳、agent 绑定线程与 vmtool 参数校验修复Arthas 4.3.1 发布详解WebSocket 心跳、agent 绑定线程与 vmtool 参数校验修复 本篇围绕 Arthas 4.3.1artha开发工具可观测性调试器性能剖析Eclipse Mosquitto 1.5.4 发布详解TLS WebSocket 证书校验修复与关键稳定性改进Eclipse Mosquitto 1.5.4 发布详解TLS WebSocket 证书校验修复与关键稳定性改进 本指南基于 Mosquitto 1.5.4物联网消息队列后端网络/通信Litestar Channels 实战指南事件流路由、WebSocket 广播与多后端发布/订阅体系Litestar Channels 实战指南事件流路由、WebSocket 广播与多后端发布/订阅体系 Channels 是 Litestar 中一组面向 事后端Web框架上一篇cytoscape.js 集合操作详解eles.union() 合并元素集合的用法与底层实现下一篇深入解析 Erlang/OTP 虚拟机 Thread Progress 机制无锁并发下的线程进度追踪与内存屏障创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考