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

如何利用SignalR检测浏览器关闭事件?MVC Razor页面场景

用SignalR实现MVC Razor页面的用户连接/断开事件检测

问题背景

试过多种jQuery、JavaScript方法检测浏览器关闭事件,但onbeforeunload和onunload方法均无效。需要在MVC Razor视图页面中,精准触发用户初始连接事件,以及用户断开页面的事件(包括浏览器关闭、意外关机等场景),如何通过SignalR实现该需求?

已尝试的代码:

window.onbeforeunload = function (event) {
  var message = 'Important: Please click on \'Save\' button to leave this page.';
  if (typeof event == 'undefined') 
  {
      event = window.event;
  }
  if (event) 
  {
    event.returnValue = message;
  }
  return message;
};

$(function () {
   $("a").not('#lnkLogOut').click(function () {
       window.onbeforeunload = null;
   });
   $(" .btn").click(function () {
       window.onbeforeunload = null;
     });
  });

解决方案

一、后端配置SignalR服务

  1. 安装SignalR包
    在项目中通过NuGet安装Microsoft.AspNetCore.SignalR包。

  2. 配置SignalR中间件
    在Startup.cs(.NET Core)中注册SignalR服务:

public void ConfigureServices(IServiceCollection services)
{
    services.AddSignalR();
    // 其他服务配置...
}

public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
    // 其他中间件配置...
    app.UseEndpoints(endpoints =>
    {
        endpoints.MapHub<UserTrackHub>("/userTrackHub");
        // 其他端点配置...
    });
}
  1. 创建用户追踪Hub类
    新建Hub类处理连接与断开事件,记录用户连接状态:
using Microsoft.AspNetCore.SignalR;
using System.Collections.Concurrent;

public class UserTrackHub : Hub
{
    // 存储用户ID与对应连接ID集合
    private static readonly ConcurrentDictionary<string, HashSet<string>> _userConnections = new ConcurrentDictionary<string, HashSet<string>>();

    public override async Task OnConnectedAsync()
    {
        var userId = Context.User.Identity.Name;
        var connectionId = Context.ConnectionId;

        // 添加用户连接记录
        _userConnections.AddOrUpdate(userId, 
            new HashSet<string> { connectionId }, 
            (key, existing) => { existing.Add(connectionId); return existing; });

        // 触发初始连接事件,比如记录日志、推送在线状态
        await Clients.All.SendAsync("UserConnected", userId);
        await base.OnConnectedAsync();
    }

    public override async Task OnDisconnectedAsync(Exception exception)
    {
        var userId = Context.User.Identity.Name;
        var connectionId = Context.ConnectionId;

        // 移除对应连接记录
        if (_userConnections.TryGetValue(userId, out var connections))
        {
            connections.Remove(connectionId);
            if (connections.Count == 0)
            {
                _userConnections.TryRemove(userId, out _);
                // 用户完全离线时触发断开事件
                await Clients.All.SendAsync("UserDisconnected", userId);
            }
        }

        await base.OnDisconnectedAsync(exception);
    }
}

二、前端Razor页面集成SignalR

在Razor视图中引入SignalR脚本并初始化连接:

<!-- 引入SignalR脚本 -->
<script src="~/lib/signalr/dist/browser/signalr.min.js"></script>
<script>
    // 初始化SignalR连接
    const connection = new signalR.HubConnectionBuilder()
        .withUrl("/userTrackHub")
        .configureLogging(signalR.LogLevel.Information)
        .build();

    // 监听服务端推送的连接事件
    connection.on("UserConnected", function (userId) {
        console.log(`用户 ${userId} 已上线`);
        // 可在此更新前端在线用户列表等
    });

    // 监听服务端推送的断开事件
    connection.on("UserDisconnected", function (userId) {
        console.log(`用户 ${userId} 已下线`);
        // 处理前端离线逻辑
    });

    // 启动连接,失败自动重试
    async function start() {
        try {
            await connection.start();
            console.log("SignalR连接建立成功");
            // 前端初始连接后的自定义逻辑
        } catch (err) {
            console.error(err);
            setTimeout(start, 5000);
        }
    }

    // 页面加载时启动连接
    start();

    // 无需依赖onbeforeunload,SignalR会自动检测所有断开场景
</script>

关键说明

  1. 替代onbeforeunload的原因
    现代浏览器对onbeforeunload/onunload有严格限制:禁止自定义提示文本,意外关机、浏览器崩溃等场景无法触发,无法精准感知断开。而SignalR基于WebSocket/长轮询机制,服务端主动检测连接状态,连接中断时自动触发OnDisconnectedAsync,覆盖所有断开场景。

  2. 多标签页处理
    Hub类中用HashSet存储同一用户的多个连接ID,确保只有用户关闭所有标签页时,才会触发完全离线事件。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.23 02:37:56