基于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
相关产品推荐
相关产品推荐

