You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何确保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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.25 20:09:23