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

用户关闭浏览器或标签页时如何自动更新数据库内用户在线状态

现有代码前置修复

你当前的登出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_active datetime类型字段,前端每隔3分钟发送一次心跳请求,更新当前登录用户的last_active为当前时间
  • 后端配置定时任务(如Linux cron),每2分钟执行一次SQL:UPDATE users SET status = 'Offline now' WHERE TIMESTAMPDIFF(MINUTE, last_active, NOW()) > 5,批量将超过5分钟无活跃的用户状态设为离线

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.28 22:06:02