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

基于PHP的单页网站用户在线/离线状态基础轮询方案需求

嘿,针对你这个单页站点的用户在线状态判定需求,我整理了一套实用的方案,完全贴合你的场景:

核心方案:前端定时心跳 + 后端内存式状态维护

因为你的站点是单页、无频繁交互,而且允许10分钟左右的误差,这个方案既轻量又能满足需求,还避开了数据库频繁写入的问题。

1. 前端实现:静默心跳发送

用户打开标签页后,不需要依赖任何交互,前端定时向后端发送心跳请求:

  • 心跳间隔:设置为5分钟(比10分钟的误差阈值短一半,避免网络波动导致误判)
  • 发送方式:用fetch或者XMLHttpRequest发送一个简单的GET请求,比如/api/user-heartbeat?userId=xxx
  • 页面可见性优化:利用浏览器的Page Visibility API减少无效请求,当标签页被隐藏时,把心跳间隔延长到8分钟(既节省资源,又保证在误差范围内)
    let heartbeatInterval = 5 * 60 * 1000; // 默认5分钟
    const userId = '当前用户唯一标识';
    
    // 监听页面可见性变化
    document.addEventListener('visibilitychange', () => {
      heartbeatInterval = document.hidden ? 8 * 60 * 1000 : 5 * 60 * 1000;
      // 重置定时器
      clearInterval(window.heartbeatTimer);
      startHeartbeat();
    });
    
    function startHeartbeat() {
      window.heartbeatTimer = setInterval(() => {
        fetch(`/api/user-heartbeat?userId=${userId}`, { 
          method: 'GET',
          cache: 'no-store' // 禁止缓存,确保后端收到真实请求
        }).catch(err => console.log('心跳发送失败:', err));
      }, heartbeatInterval);
    }
    
    // 页面加载时启动心跳
    window.addEventListener('load', startHeartbeat);
    

2. 后端实现:内存缓存维护在线状态

既然不能用数据库,我们可以用内存存储(比如Node.js的Map、Java的ConcurrentHashMap,或者轻量的Redis——它属于内存级存储,比数据库轻便太多)来维护用户的最后心跳时间:

  • 存储结构:键为userId,值为最后心跳的时间戳
  • 定时清理任务:后端启动一个每10分钟执行一次的定时任务,遍历所有用户记录,把最后心跳时间距离当前超过10分钟的标记为离线(或直接删除记录,下次心跳再重新添加)
  • 接口实现:接收前端的心跳请求,更新对应userId的时间戳即可
    // Node.js示例,用Map存储
    const userOnlineStatus = new Map();
    
    // 心跳接口
    app.get('/api/user-heartbeat', (req, res) => {
      const { userId } = req.query;
      if (!userId) return res.status(400).send('缺少userId');
      userOnlineStatus.set(userId, Date.now());
      res.send('心跳接收成功');
    });
    
    // 定时清理离线用户,每10分钟执行一次
    setInterval(() => {
      const now = Date.now();
      const offlineThreshold = 10 * 60 * 1000; // 10分钟阈值
      for (const [userId, lastHeartbeat] of userOnlineStatus.entries()) {
        if (now - lastHeartbeat > offlineThreshold) {
          userOnlineStatus.delete(userId);
          // 可按需触发离线通知逻辑
          console.log(`用户${userId}已离线`);
        }
      }
    }, 10 * 60 * 1000);
    

3. 状态查询逻辑

如果需要查询某个用户的在线状态,直接从内存缓存中判断:

  • 如果userOnlineStatus中存在该userId,且最后心跳时间距离当前不超过10分钟,则视为在线
  • 否则视为离线

4. 边缘场景处理

  • 浏览器崩溃/强制关闭:前端无法发送最后一次心跳,后端会在10分钟后自动标记为离线,符合误差要求
  • 网络波动:某次心跳发送失败不影响,前端定时器会继续尝试,只要10分钟内有一次成功,就会维持在线状态
  • 多标签页登录:多个标签页的重复心跳只会更新最新时间戳,不会产生冲突,反而提升了状态的可靠性

内容的提问来源于stack exchange,提问作者Charles Raiser

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.21 07:21:00