多日持久信号器连接模式

Pattern for multiday persistent signalr connection

连接到 SignalR 并在页面上永久保持 link 的正确 JavaScript 模式是什么,无论人们是否休眠计算机或互联网连接不稳定。

文档只是说使用:

$.connection.hub.start()
    .done(function(){ console.log('Now connected, connection ID=' + $.connection.hub.id); })
    .fail(function(){ console.log('Could not Connect!'); });
});

但这似乎没有考虑断开连接和其他问题。

另外,没有捕捉到session过期需要重新登录的问题

我认为可以做到这一点的唯一方法是使用存储每个连接客户端的连接信息的背板。也就是说,他们永远不会 "Stay Connected" 如果他们失去互联网或休眠,您所能做的就是 "reconnect" 如果断开连接,您将必须持续存储任何状态信息,您不能在 "disconnect" 事件中执行此操作,因为到那时可能为时已晚。一种选择是持续将状态信息流式传输到 Redis 缓存,并以更合理的间隔定期将其发送到背板,或者在断开连接甚至触发时发送。

鉴于 SignalR 是基于连接的 client/server 解决方案,您不能期望长期持续打开连接。因此,正如 Kelso Sharp 在他的回答中所写,您唯一能做的就是管理连接生命周期的事件。

查看 signalR 连接的所有生命周期事件的文档: https://www.asp.net/signalr/overview/guide-to-the-api/hubs-api-guide-javascript-client#connectionlifetime

因此,如果我们不将注意力集中在如何建立永不失败的持久连接上,我们可以通过在后台巧妙地管理断开连接、重新加载等操作,专注于给用户留下这样的印象。

这是一个图表,显示了我将如何设置它,即使您没有指定是什么导致您的集线器将数据推送到客户端,但我认为它可能类似于此图表。这里的想法是你将相同的状态推送到某种状态提供者——即缓存、网络 api 存储,这样你就可以在任何给定时间获得整套数据。当 ui 加载或断开连接时,它应该向此提供程序发出请求以重新获得状态,然后它应该重新连接到集线器。

如果数据一致性是个问题,您可以对状态进行版本控制,在 ui 中保留一个本地副本,然后在重新连接时进行审核。这样你就可以看到你是否错过了什么,在这种情况下你会向州提供者发出追赶请求。

为了处理事件,您只需在客户端的一些函数中挂钩: //这将触发连接周期内的所有状态更改:

$.connection.hub.stateChanged(function (change) {
    if (change.newState === $.signalR.connectionState.reconnecting) {
        console.log("liveFeed is reconnecting!");
    }
    else if (change.newState === $.signalR.connectionState.connected) {
        console.log("liveFeed is connected!");
    }
});

//断开与集线器的连接时触发。

$.connection.hub.disconnected(function () {
   console.log('Connection disconnected')
});

通过重试包装对服务器的所有调用,找出如何使会话过期:

function callServer(call) {
  function err(r?: Error) {
     var output = $.Deferred();
     if (r &&
        r.message &&
        (r.message.startsWith("Caller is not authorized to invoke the") ||
           r.message.startsWith("The user identity cannot change during "))) {
        $('#login-dialog')
           .one('hide.bs.modal',
              () => {
                 hub.connection.stop();
                 $.connection.hub.start()
                    .then(() => hub.server.run(call))
                    .then(output.resolve, output.reject);
              })
           .modal('show');
        return output;
     }
     // ReSharper disable once SuspiciousThisUsage
     return output.rejectWith(this, <any>arguments);
  }

  return $.connection.hub.start()
     .then(() => hub.server.run(call))
     .then(null, err);
}

这假设有一个 bootstrap 模态对话框 #login-dialog 关闭时表示它已处理重新登录。