SignalR 2.4.1使用onclose报错:Cannot read properties of undefined (reading 'onclose')
SignalR 2.4.1 处理浏览器关闭时的用户上下文清理问题
错误原因分析
你遇到的Cannot read properties of undefined (reading 'onclose')错误,是因为SignalR 2.x 客户端没有onclose方法——这个API是ASP.NET Core SignalR(即SignalR 3.0+版本)新增的,旧版2.4.1并不支持。
解决方案
1. 正确绑定SignalR断开连接事件
在SignalR 2.x中,需要使用disconnected方法来监听连接断开事件:
// 替换你原来的onclose代码,改用SignalR 2.x原生的断开事件绑定 SignalrConnection.disconnected(function() { console.log("SignalR连接已断开"); // 这里可以处理断开后的基础逻辑,但注意:浏览器关闭时这个事件可能不会即时触发 });
2. 主动监听浏览器关闭事件,实时通知后端清理
浏览器/标签页关闭时,直接通过SignalR异步调用可能会被浏览器中断,推荐使用navigator.sendBeacon(专为页面卸载时发送请求设计,浏览器会确保请求完成),或者结合SignalR的主动调用:
客户端代码实现
// 监听浏览器卸载事件(关闭标签页/窗口) window.addEventListener('beforeunload', function(event) { // 确保已获取到连接ID和公司ID if (mHubConnectionId && typeof companyid !== 'undefined') { // 方式1:使用sendBeacon调用后端API(推荐,可靠性更高) const formData = new FormData(); formData.append('connectionId', mHubConnectionId); formData.append('companyId', companyid); navigator.sendBeacon('/api/Chat/CleanUserContext', formData); // 方式2:尝试SignalR主动调用(可能因浏览器中断请求而失败,仅作备选) // ChatProxy.invoke("CleanUserContext", mHubConnectionId) // .fail(err => console.log("发送清理请求失败:", err)); } });
后端Hub与API实现
Hub中添加主动清理方法
public class CoolHub : Hub { // 你的Connect方法保持不变 public void Connect(int companyId) { // 将用户上下文(ConnectionId、CompanyId等)存入数据库 // ... 你的业务代码 } // 主动清理用户上下文的方法 public void CleanUserContext(string connectionId) { // 根据ConnectionId从数据库删除对应的用户上下文 // ... 你的业务代码 } // 补充:SignalR自带的断开回调(处理未主动通知的场景,比如网络异常) public override Task OnDisconnected(bool stopCalled) { // stopCalled=true:客户端主动调用stop断开;false:连接意外断开(如浏览器关闭、网络中断) if (!stopCalled) { // 根据Context.ConnectionId清理数据库中的用户上下文 // ... 你的业务代码 } return base.OnDisconnected(stopCalled); } }
可选:后端API接口(配合sendBeacon使用)
如果使用sendBeacon,需要添加对应的API控制器:
[Route("api/[controller]")] public class ChatController : Controller { private readonly YourDbContext _dbContext; public ChatController(YourDbContext dbContext) { _dbContext = dbContext; } [HttpPost("CleanUserContext")] public IActionResult CleanUserContext(string connectionId, int companyId) { // 根据connectionId和companyId删除数据库中的用户上下文 var userContext = _dbContext.UserContexts.FirstOrDefault(u => u.ConnectionId == connectionId && u.CompanyId == companyId); if (userContext != null) { _dbContext.UserContexts.Remove(userContext); _dbContext.SaveChanges(); } return Ok(); } }
关键注意事项
navigator.sendBeacon仅支持POST请求,且数据格式限制为FormData、Blob等,不能直接发送JSON(如需JSON可转为Blob)。- SignalR的
OnDisconnected方法会在连接超时后触发(默认30秒),可以作为主动通知的兜底方案,确保用户上下文最终被清理。 - 确保
mHubConnectionId和companyid在beforeunload事件作用域内可访问(比如声明为全局变量或通过闭包传递)。
内容的提问来源于stack exchange,提问作者Sana
相关产品推荐
相关产品推荐

