如何维护页面之间的 WebSockets 连接?

IT技术 javascript html websocket
2021-01-17 16:40:06

在我的一个脚本中,我有以下代码:

var webSocket = window.WebSocket || window.MozWebSocket;
window.ws = new webSocket('ws://64.121.210.140:2585/consoleappsample', 'my-protocol');

哪个工作正常。但是,当用户更改页面时,我必须重新建立连接。我相信这会导致我的代码出现问题,因为如果客户端将数据发送到服务器然后更改页面,则可能无法接收到数据并且会发生竞争条件。

我试图将 放在window.ws全局范围内,但它似乎没有解决问题。有什么方法可以让 WebSockets 连接在页面之间保持不变,从而不需要不断重新建立连接?

4个回答

你提到的全局作用域总是和 JavaScript Context 相关的,每个窗口都会创建一个 Context(并且在从内存中卸载文档时销毁)。因此,您的努力是无用的:如果用户更改页面,您将无法保持连接打开。当然,您可以将您的 web 应用程序作为“单页”应用程序,使用 XMLHttpRequest/ajax/WebSocket 加载所有数据。因此,离开页面意味着离开/关闭应用程序,并且关闭套接字是有意义的。

另一种旧方法可能是将您的页面放在一个框架中,用户仅在框架中导航(即使它占据了整个窗口的大小)。通过这种方式,您可以在最顶部的窗口中创建 WebSocket,该窗口永远不会改变(这也意味着地址栏中显示的 URL 将始终相同)。

这么说,我同意@dystroy:您的应用程序应该始终能够处理这种情况 - 用户可能会遇到一些网络问题并暂时失去连接,即使它没有离开页面。

我知道这是一个旧的回复,但是如果一个应用程序的用户总是在更改页面,这不会通过不断的断开连接和重新连接来打击 Web 套接字服务器吗?
2021-03-15 16:40:06
使用框架技巧,有没有办法让地址栏中的位置反映包含可导航内容的框架内的导航位置?自动地?内容中的链接保持简单的hrefs?
2021-03-22 16:40:06
您可以尝试使用History API做一些事情
2021-04-05 16:40:06

您可以尝试在 Shared WebWorker 中创建 WebSocket 连接,它允许来自同一域的多个页面共享一个执行上下文。但是,尚不清楚 Shared Workers 是否在页面重新加载或替换时持续存在Do Shared Web Workers persist over a single page reload, link navigation

此外,共享 WebWorker 目前对浏览器的支持有限 (webkit 和 Opera)。

更新

由于单个共享 Web Worker 可以为多个页面提供服务,因此实现比普通 Web Worker 稍微复杂一些。

这是一个共享的 Web Worker 示例,它使用 WebSockets 并且可以在

首先是 HTML:

<!DOCTYPE html>
<html>
<body>
<script>
    var worker = new SharedWorker("shared.js");
    worker.port.addEventListener("message", function(e) {
        console.log("Got message: " + e.data);
    }, false);
    worker.port.start();
    worker.port.postMessage("start");
</script>
</body>
</html>

在 中实现共享工作者的 Javascript shared.js

var ws = null
var url = "ws://" + location.hostname + ":6080"
self.addEventListener("connect", function(e) {
    var port = e.ports[0]
    port.addEventListener("message", function(e) {
        if (e.data === "start") {
            if (ws === null) {
                ws = new WebSocket(url);
                port.postMessage("started connection to " + url);
            } else {
                port.postMessage("reusing connection to " + url);
            }
        }
    }, false);
    port.start();
}, false);

我已经验证这在 Chrome 52 中有效。

我有个疑问。在这种情况下,webworkers 中没有 websocket 支持,我们如何维护应用程序的上下文。
2021-03-23 16:40:06
@kongaraju,您可以通过 Chrome 中的 Web Workers 使用 WebSockets,并且有一个 Mozilla 错误可以在 Firefox 中实现对此的支持:bugzilla.mozilla.org/show_bug.cgi? id=504553
2021-03-25 16:40:06
很好的建议,不幸的是对我没有用。它缺乏跨浏览器的支持caniuse.com/#feat=sharedworkers
2021-03-26 16:40:06
@ShkarbatovDmitriy 我刚刚在 Chrome 52 上尝试过它,它按预期工作(刷新单页重新创建,刷新两个页面之一导致重用)。请注意,您需要修改我的示例以在连接处理程序之外存储 websocket 连接状态。此外,您的页面和 websocket 目标可能需要位于 localhost 以外的其他位置。
2021-03-28 16:40:06
@kongaraju,我刚刚添加了一个示例,我已经验证它可以在 Chrome 20 中运行,并且确实从 Shared WebWorker 建立了到服务器的 WebSocket 连接。
2021-04-12 16:40:06

不幸的是,无需更改您在 SPA 应用程序中的站点的最干净的解决方案是仅使用一个 ServiceWorker 即可获得的,因为它在后台完成工作(也关闭选项卡)并且它还解决了多个选项卡的问题。我说“不幸”是因为它们仍然与大多数浏览器不兼容。

我自己找到的唯一解决方案是在服务器端对套接字通道进行分组,并创建一个队列以保存因更改页面而丢失的消息。在这种情况下,您有一些虚拟频道。

您可以在 localstorage 中记录与 websocket 服务器的对话,该对话在页面加载时持续存在。