javascript - SignalR 在 IE 和 Firefox 上与 POST 请求断开连接

标签 javascript c# internet-explorer firefox signalr

我正在我的网站上设置一个通知系统 (ASP.NET MVC)。它需要是无状态的,所以我选择了 SignalR。 通知仅来自服务器端,我想在刷新新页面后显示它,而不是实时显示。通常它是一个将被触发并向客户端发送通知,然后重定向或显示 View 的 ActionResult。

这是它进行的方式:

  1. 服务器向客户端发送消息。
  2. 客户端将其存储到浏览器本地存储。
  3. 重定向后,它会显示来自本地存储的通知。

我将 SignalR 2.2.1 与 JQuery 1.9.1 结合使用

NotificationHub.cs

[HubName("notificationHub")]
public class NotificiationHub : Hub
{
    public static void Send(string connectionId, string name, string message)
    {
        var hubContext = GlobalHost.ConnectionManager.GetHubContext<NotificiationHub>();
        hubContext.Clients.Client(connectionId).sendNotification(name, message);
    }
}

_Layout.cshtml js

<script>
getNotificationStack = function () {
    if (localStorage.getItem("notifications") != null) {
        return JSON.parse(localStorage.getItem("notifications"));
    }
    return [];
}

checkNotification = function () {
    var notificationStack = getNotificationStack();

    var count = notificationStack.length;
    for (var i = 0; i < count; i++) {
        window.alert(notificationStack.pop());
    }
    localStorage.removeItem("notifications");

}

initHubConnection = function () {
    // Reference the auto-generated proxy for the hub.
    $.connection.hub.logging = true;

    var notification = $.connection.notificationHub;
    notification.client.sendNotification = function (name, message) {
        var notificationStack = getNotificationStack();
        notificationStack.push(name + ": " + message);
        localStorage.setItem("notifications", JSON.stringify(notificationStack));
    };

    // Start the connection.
    $.connection.hub.start().done(function () {
        // allows to send notification to one tab through connectionId
        document.cookie = "connectionId=" + $.connection.hub.id;
    });
}

$(function () {
    checkNotification();
    initHubConnection();
});
</script>

MyView.cshtml

@using (Html.BeginForm("TestSendNotification", "Home", FormMethod.Post))
{
    <input type="submit" value="Press that button"/>
}

HomeController.cs

public class HomeController : Controller
{
    public ActionResult Index()
    {
        return View();
    }

    public ActionResult TestSendNotification()
    {
        NotificiationHub.Send(Request.Cookies["connectionId"].Value, "Info", "Oh you pressed that!");

        return RedirectToAction("Index", "Home");
    }
}

它在 Chrome 中的效果很好,但在 Microsoft Edge 和 Firefox 中却不行。

Microsoft Edge 行为: 已建立连接,但客户端未收到消息。

-> 注意:如果我调试我的应用程序并在发送通知后等待足够长的时间,我就会成功收到消息。 好像发送消息时间过长,然后页面正在刷新导致连接丢失,客户端无法接收到消息...

Firefox 行为: 每次单击按钮(= 发送 POST)时,连接都会丢失,客户端当然无法接收消息。我不知道为什么会这样!

如果我使用的是 ajax POST,它运行良好,但这不是我想要的。

############################################# ###############

2017 年 2 月 16 日更新: 不幸的是,我们不能对这个库使用简单的 http POST,它必须是 ajax POST 才能正常工作。 在他们的 git 上得到了答案:https://github.com/SignalR/SignalR/issues/3869#issuecomment-280074464

最佳答案

我们也必须处理这个问题。

解决方案是:跟踪新的和旧的 connectionIds。 在 Controller 内部:

public ActionResult RegisterConnectionId(string newConnectionId, string oldConnectionId)
{
    Session["SignalRConnectionId"] = newConnectionId;

    if(!string.IsNullOrEmpty(oldConnectionId))
        RemapConnectionId(newConnectionId, oldConnectionId);        
}

我们引入了一个过期的 MemoryCache 作为旧 ConnectionId 的受害者缓存。

public void RemapConnectionId(string newConnectionId, string oldConnectionId)
{
    if(newConnectionId != null && newConnectionId != oldConnectionId)
        MemoryCache.Default.Set(oldConnectionId, newConnectionId, ...);
}

您可以从旧的 ConnectionId 获取当前的 ConnectionId 并像这样处理潜在的 MULTIPLE 更改:

public string ResolveConnectionId(string connectionId)
{            
    while (!IsEligibleConnectionId(connectionId) && !string.IsNullOrEmpty(connectionId))
        connectionId = MemoryCache.Default.Get(connectionId) as string;


    return connectionId;
}

当然,你需要在 hub 启动时向服务器提供新的和旧的连接 ID。

关于javascript - SignalR 在 IE 和 Firefox 上与 POST 请求断开连接,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/42231774/

相关文章:

javascript - 数组 JavaScript 输出

javascript - 错误 : Attempt to run compile-and-go script on a cleared scope

javascript - 使用 Angular 2 RC5 路由器,在给定 ActivatedRouteSnapshot 的情况下,我如何导航?

c# - 匿名类可以实现接口(interface)吗?

c# - 使用 WCF 的身份验证服务

html - 为什么我的文档模式是: IE7 standards in HTML5 page?

javascript - 如何等待ng-repeat的所有元素显示出来

c# - 使用逐字字符串文字和 appendformat 时出现索引(从零开始)错误

IE Bug 中的 jQuery .clone() .html()

ajax - 动态加载内容然后前进和后退时 Internet Explorer 和 Firefox 的差异