SignalR 长轮询 5 秒后断开

SignalR long-polling is disconnected in 5 seconds

我的应用程序在公司网络下运行(丑陋的代理和东西)。而且效果不是很好。我希望使用 https 会有所帮助,但事实并非如此。这是我在日志中看到的一个奇怪的模式:

[14:13:32 GMT+0600 (N. Central Asia Standard Time)] SignalR: Client subscribed to hub 'modemshub'.
[14:13:32 GMT+0600 (N. Central Asia Standard Time)] SignalR: Negotiating with '/signalr/negotiate?clientProtocol=1.5&connectionToken=6aktO0sramoQKhQ9DC7Cs7EbXMUou8LooQRxfup4R0oZCHpBmWBFjyLup%2F3wJLloR8GtJEiUk10YOZJBaSqN8aiGAfXRR4G9hujTFTyiJiz%2FyJ4oMlBIdxqeCc5anI6k&connectionData=%5B%7B%22name%22%3A%22modemshub%22%7D%5D'.
[14:13:32 GMT+0600 (N. Central Asia Standard Time)] SignalR: longPolling transport starting.
[14:13:32 GMT+0600 (N. Central Asia Standard Time)] SignalR: Opening long polling request to 'https://example.com/signalr/connect?transport=longPolling&clientProt…rlCzGHl5kVLClT5ex8&connectionData=%5B%7B%22name%22%3A%22modemshub%22%7D%5D'.
[14:13:33 GMT+0600 (N. Central Asia Standard Time)] SignalR: Long poll complete.
[14:13:33 GMT+0600 (N. Central Asia Standard Time)] SignalR: LongPolling connected.
[14:13:33 GMT+0600 (N. Central Asia Standard Time)] SignalR: longPolling transport connected. Initiating start request.
[14:13:33 GMT+0600 (N. Central Asia Standard Time)] SignalR: Opening long polling request to 'https://example.com/signalr/poll?transport=longPolling&clientProtoco…rlCzGHl5kVLClT5ex8&connectionData=%5B%7B%22name%22%3A%22modemshub%22%7D%5D'.
[14:13:33 GMT+0600 (N. Central Asia Standard Time)] SignalR: The start request succeeded. Transitioning to the connected state.
[14:13:38 GMT+0600 (N. Central Asia Standard Time)] SignalR: Long poll complete.
[14:13:38 GMT+0600 (N. Central Asia Standard Time)] SignalR: Stopping connection.
[14:13:38 GMT+0600 (N. Central Asia Standard Time)] SignalR: Fired ajax abort async = true.

因此连接建立,5 秒后中止(而 ConnectionTimeout 等于 110 秒)。并且这种模式一次又一次地重复。太奇怪了。

背景

根据Asp.net

SignalR uses the transport API to create a transport connection, and the transport API depends on the existence of a physical network connection to create the transport connection. The transport connection ends when SignalR terminates it or when the transport API detects that the physical connection is broken.

Physical connections might be slow or there might be interruptions in connectivity. Depending on factors such as the length of the interruption, the transport connection might be dropped. SignalR then tries to re-establish the transport connection. Sometimes the transport connection API detects the interruption and drops the transport connection, and SignalR finds out immediately that the connection is lost. In other scenarios, neither the transport connection API nor SignalR becomes aware immediately that connectivity has been lost. For all transports except long polling, the SignalR client uses a function called keepalive to check for loss of connectivity that the transport API is unable to detect.

Troubleshooting

请注意, SignalR 2.1 为 长轮询 引入了保持活动状态。如果某些东西干扰了分块的 HTTP 响应,这可能会有问题。如果您想要 disable keepalive 功能,请将 KeepAlive 设置为 nullKeepalive 功能自动 disabled 长轮询 传输。

如果您是 using a Self-Host,请改用以下 和 3 个参数

GlobalHost.Configuration.ConnectionTimeout = new TimeSpan(0,0,110);
GlobalHost.Configuration.DisconnectTimeout = new TimeSpan(0,0,30);
GlobalHost.Configuration.KeepAlive = new TimeSpan(0,0,10);

作为支持长轮询的保持活动 "like" 功能的不同替代方法,创建一个服务器方法并将其命名为 Ping:

public class MyHub : Hub
{
    public void Ping()
    {
    }
}

然后,在客户端上创建一个时间间隔,您将在其中 Ping 服务器:

var proxy = $.connection.myHub,
    intervalHandle;  
...
$.connection.hub.disconnected(function() {
    clearInterval(intervalHandle);
});  
...  
$.connection.hub.start().done(function() {
    // Only when long polling
    if($.connection.hub.transport.name === "longPolling") {
        // Ping every 10s
        intervalHandle = setInterval(function() {
            // Ensure we're connected (don't want to be pinging in any other state).
            if($.connection.hub.state === $.signalR.connectionState.connected) {
                proxy.server.ping().fail(function() {
                    // Failed to ping the server, we could either try one more time to ensure we can't reach the server
                    // or we could fail right here.
                    TryAndRestartConnection(); // Your method
                });
            }
        }, 10000); 
    }
});

希望对你有用

假定 Understanding and Handling Connection Lifetime Events in SignalR 中提供的提示,您可以在其中使用好的解决方案来处理基于网络问题的连接生命周期。此外,在 SignalR 的问题中,我为您找到了以下适用于长轮询的解决方案。

您可以在 ConfigurationManager 上设置 KeepAlive 属性,SignalR 将在指定的时间间隔内发送一个空数据帧(基于传输)以保持连接处于活动状态(查看 Allow host to specify keep alive times ).当前的超时机制使流式传输协议没有什么不同。

似乎此行为是由 SignalR 2.1 中的错误引起的。报告了一个类似的错误:https://github.com/SignalR/SignalR/issues/3557 所以我们将 SignalR 降级到 2.0.3,此行为消失了。