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

如何在Django体育流媒体站点实现授权用户实时观看人数统计?

最优实现方案

一、先搞定授权访问基础

  • 直播页面视图必须做权限校验:
    • 普通登录用户:给函数视图加@login_required装饰器,类视图用LoginRequiredMixin,拦截未登录用户跳转登录页。
    • 细分权限(比如仅付费用户可看):自定义装饰器或Mixin,检查用户模型的权限字段(比如User.is_subscribed)或关联的订阅记录,无权限直接返回403或引导到付费页面。
    • 流媒体地址保护:如果用第三方流媒体服务,让Django生成带有效期的签名URL,只有授权用户能拿到有效地址,防止直接盗链。

二、在线观看人数统计(优于JS轮询的方案)

方案1:WebSocket + Django Channels(首推)

这是实时性最高、服务器压力最小的方案,适合需要即时更新在线人数的场景:

  • 安装Django Channels,用ASGI服务器(比如Daphne)替换WSGI,支持WebSocket双向通信。
  • 定义WebSocket消费者:
    • 用户进入直播页时,前端建立WebSocket连接,Django Channels会自动识别登录用户的Cookie信息。
    • 消费者先验证用户权限(和直播视图的校验逻辑一致),通过后把用户加入对应直播的分组(比如live_stream_123),用Redis存储该直播的在线用户ID集合(避免服务器重启丢失数据,分布式部署必须用Redis)。
    • 用户关闭页面或断开连接时,消费者把用户从分组移除,更新在线人数并主动推送给所有在线用户。
  • 核心代码片段:
    # consumers.py
    import json
    from channels.generic.websocket import AsyncWebsocketConsumer
    from channels.db import database_sync_to_async
    from django.contrib.auth import get_user_model
    import redis
    
    User = get_user_model()
    redis_client = redis.Redis(host='localhost', port=6379, db=0)
    
    class LiveStreamConsumer(AsyncWebsocketConsumer):
        async def connect(self):
            self.stream_id = self.scope['url_route']['kwargs']['stream_id']
            self.stream_group_name = f'live_stream_{self.stream_id}'
            user = self.scope['user']
    
            # 权限校验
            if not user.is_authenticated or not user.can_watch_live:
                await self.close()
                return
    
            # 加入分组并更新Redis在线用户
            await self.channel_layer.group_add(self.stream_group_name, self.channel_name)
            redis_client.sadd(f'online_users_{self.stream_id}', user.id)
            
            # 推送当前在线人数
            await self.broadcast_online_count()
            await self.accept()
    
        async def disconnect(self, close_code):
            await self.channel_layer.group_discard(self.stream_group_name, self.channel_name)
            redis_client.srem(f'online_users_{self.stream_id}', self.scope['user'].id)
            await self.broadcast_online_count()
    
        async def broadcast_online_count(self):
            count = redis_client.scard(f'online_users_{self.stream_id}')
            await self.channel_layer.group_send(
                self.stream_group_name,
                {'type': 'send_count', 'count': count}
            )
    
        async def send_count(self, event):
            await self.send(text_data=json.dumps({'online_count': event['count']}))
    
    前端JS:
    const streamId = '123';
    const socket = new WebSocket(`ws://${window.location.host}/ws/live/${streamId}/`);
    
    socket.onmessage = e => {
        const data = JSON.parse(e.data);
        document.getElementById('online-count').textContent = `当前观看:${data.online_count}人`;
    };
    
    socket.onclose = () => console.error('直播连接已断开');
    

方案2:Redis + 短轮询(折中方案)

如果暂时不想引入Channels,可以用Redis缓存在线用户,结合短轮询(比普通轮询高效):

  • 用户进入直播页时,Django把用户ID加入Redis的有序集合,设置5分钟过期时间,前端每隔10秒发送AJAX请求到统计接口。
  • 统计接口从Redis获取该直播的在线用户数(统计未过期的ID数量),同时刷新当前用户的过期时间。
  • 用户关闭页面时,前端发送退出请求移除ID;直接关页的话,Redis过期时间会自动清理无效用户。

三、方案对比

  • WebSocket方案:实时性拉满,服务器主动推送,用户体验好,但需要配置ASGI和Channels,有一定学习成本。
  • Redis+短轮询:实现简单,不用改服务器架构,但有10秒左右延迟,服务器压力比WebSocket大,但比普通轮询小很多。

内容的提问来源于stack exchange,提问作者Stepan.Basharov

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.11 02:35:35