用户关闭浏览器或标签页时如何自动更新数据库内用户在线状态
现有代码前置修复
你当前的登出SQL语句存在语法错误,缺少=号,需先修正,否则即使触发请求也无法正常更新用户状态。同时原直接拼接参数的写法存在SQL注入风险,后续改造中会同步修复。
1. 前端sendBeacon实现
使用beforeunload事件触发(注意此处用的是beforeunload而非你要求规避的unload事件,符合你的需求限制),sendBeacon是浏览器专门为页面卸载场景设计的API,请求异步发送不阻塞页面关闭,送达率远高于普通Ajax。
首先在登录后的公共页面头部注入当前用户的唯一ID:
<!-- 确保所有登录后可访问的页面都加载这段代码 --> <script> // 从后端PHP的登录用户信息中取出unique_id注入到JS变量,自动转义避免XSS const currentUserId = <?php echo json_encode($row['unique_id'], JSON_NUMERIC_CHECK); ?>; </script>
添加事件监听逻辑:
window.addEventListener('beforeunload', () => { // 用FormData构造请求参数,sendBeacon支持直接传递该对象 const reqData = new FormData(); reqData.append('logout_id', currentUserId); // 替换路径为你实际的登出接口地址 navigator.sendBeacon('/logout.php', reqData); });
2. 后端登出接口适配
修改你的logout.php代码,适配sendBeacon发送的POST请求,同时修复注入和语法问题:
<?php // 引入你原有数据库连接逻辑 include 'db_conn.php'; $status = "Offline now"; // sendBeacon发送POST请求,从$_POST中取参数,做基础校验 $logoutId = $_POST['logout_id'] ?? ''; if (is_numeric($logoutId)) { // 用预处理语句避免SQL注入 $stmt = mysqli_prepare($conn, "UPDATE users SET status = ? WHERE unique_id = ?"); mysqli_stmt_bind_param($stmt, "si", $status, $logoutId); mysqli_stmt_execute($stmt); mysqli_stmt_close($stmt); } // 不需要返回响应,sendBeacon不处理返回结果 ?>
3. 兜底优化方案
sendBeacon存在小概率触发失败的场景(如浏览器强制结束进程、设备断电等),可加一层双重保险机制:
- 给
users表新增last_activedatetime类型字段,前端每隔3分钟发送一次心跳请求,更新当前登录用户的last_active为当前时间 - 后端配置定时任务(如Linux cron),每2分钟执行一次SQL:
UPDATE users SET status = 'Offline now' WHERE TIMESTAMPDIFF(MINUTE, last_active, NOW()) > 5,批量将超过5分钟无活跃的用户状态设为离线
内容的提问来源于stack exchange,提问作者Temal
相关产品推荐
相关产品推荐

