如何确保Django Channels的WebsocketConsumer无论何种关闭方式都执行操作?
解决WebsocketConsumer关闭浏览器时disconnect不触发的问题
浏览器直接关闭标签页或整个浏览器时,WebSocket连接可能会被TCP直接断开,而非通过标准的关闭帧握手流程,这就导致服务端的disconnect方法无法被及时触发。要实现无论何种关闭方式都执行清理操作,可以通过以下几种方案解决:
1. 实现应用层心跳检测
通过客户端定时发送心跳消息,服务端维护连接的活跃状态,超过阈值未收到心跳则判定连接失效,执行清理操作。
服务端代码示例
from channels.generic.websocket import WebsocketConsumer import threading import time from django.core.cache import cache class MyConsumer(WebsocketConsumer): def connect(self): # 假设已通过认证,用用户ID生成唯一键 self.user_cache_key = f"ws_user_{self.scope['user'].id}" self.store_session_data() # 启动心跳检测线程 self.heartbeat_monitor = threading.Thread(target=self._check_heartbeat) self.heartbeat_monitor.daemon = True self.heartbeat_monitor.start() self.accept() def _check_heartbeat(self): # 每30秒检查一次心跳状态 while True: time.sleep(30) last_active = cache.get(f"{self.user_cache_key}_last_active") # 超过60秒未收到心跳,判定连接已断开 if not last_active or time.time() - last_active > 60: self.clean_session_data() break def receive(self, text_data): if text_data.strip() == "heartbeat": # 更新活跃时间,超时设为120秒 cache.set(f"{self.user_cache_key}_last_active", time.time(), timeout=120) def disconnect(self, close_code): self.clean_session_data()
客户端JavaScript示例
const socket = new WebSocket('ws://your-server-endpoint'); // 每30秒发送一次心跳 const heartbeatInterval = setInterval(() => { if (socket.readyState === WebSocket.OPEN) { socket.send('heartbeat'); } else { clearInterval(heartbeatInterval); } }, 30000); socket.onclose = () => { clearInterval(heartbeatInterval); };
2. 利用缓存自动过期机制
存储用户数据时设置合理的过期时间,结合心跳刷新过期时间,即使disconnect未触发,缓存也会自动清理失效数据。
def store_session_data(self): user_session_data = {"chat_room_id": "123", "unread_count": 0} # 初始设置2分钟过期 cache.set(self.user_cache_key, user_session_data, timeout=120) def receive(self, text_data): if text_data.strip() == "heartbeat": # 收到心跳后刷新缓存过期时间 cache.touch(self.user_cache_key, timeout=120)
3. 配置服务器TCP Keepalive
调整服务器(如Daphne、Nginx)的TCP Keepalive参数,让服务器主动探测死连接,触发disconnect方法:
- Daphne配置:启动时添加参数
--tcp-keepalive,启用TCP层面的保活探测。 - Nginx反向代理配置:在WebSocket代理的location块中添加:
proxy_http_version 1.1; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection "upgrade"; proxy_read_timeout 60s; proxy_send_timeout 60s;
总结
心跳检测是最可靠的应用层解决方案,配合缓存自动过期和服务器层面的TCP保活配置,能够覆盖浏览器直接关闭、网络中断等各种连接异常场景,确保用户相关缓存数据被及时清理。
内容的提问来源于stack exchange,提问作者Guilherme
相关产品推荐
相关产品推荐

