父窗口上下文中来自iframe的Websocket连接

问题描述 投票:0回答:1

我在页面内有一个页面和一个iframe。两者都托管在同一个域中。我完全控制iframe,但没有父页面的控件。

Image

所以我需要从iframe建立一个websocket连接,但是在父窗口的上下文中,当我导航出iframe(到父页面的其他菜单项)时,保持它活着。

(参见图片)就像在A.html中建立连接一样,并在导航到B和C时保持活着状态。

那可能吗?

javascript websocket socket.io
1个回答
1
投票

简短回答:

直接脚本注入父窗口仍然可能是一个更优雅的解决方案。

答案很长:

Websocket只是一种与服务器的连接。一旦你创建它 - 它会一直存在于浏览器的标签中,如果你卸载创建websocket的脚本,它就不会被破坏。

在iframe中创建websockets的两个问题:

  1. 每次加载相同的iframe内容时,您可能不希望创建新的websocket连接。
  2. 卸载iframe后 - 所有websocket的事件处理程序都会丢失(如onopen,onclose,onmessage等)。

您可以尝试在主窗口上创建websocket工厂。该工厂的实例将负责:

  1. 使用iframe提供的数据创建websocket并将其存储在内部集合属性中
  2. clone提供了websocket事件处理程序,因此即使卸载原始源也可以访问它们。如果事件处理程序很简单,它将正常工作。

函数克隆存在一些已知问题 - 即,如果它们使用iframe脚本中定义的外部闭包 - 那么闭包将会丢失。您可能想要对克隆库进行研究。

main.js(在主index.html中加载):

var socketsCollection = new SocketsCollection();

function SocketsCollection() {
    this.collection = {};

    this.add = function(key, obj) {
        if (this.exists(key)) return;

        // clone websocket event handlers
        // PS: this is not the best solution to clone a function. Need a better research here
        eval("var onopen = " + obj.onopen.toString());
        eval("var onclose = " + obj.onclose.toString());
        eval("var onmessage = " + obj.onmessage.toString());

        // create websocket
        var ws = new WebSocket(obj.url);
        ws.onopen = function(e) {
            onopen(e, key, ws);
        };
        ws.onclose = function(e) {
            onclose(e, key, ws);
        }
        ws.onmessage = function(e) {
            onmessage(e, key, ws);
        }

        this.collection[key] = {
            key: key,
            ws: ws
        };

        // test websocket is alive
        var self = this;
        var counter = 1;
        window.setInterval(function () {
            console.log('testing ' + key);
            self.collection[key].ws.send('ping # ' + counter + ' websocket ' + key);
            counter++;
        }, 2000);  
    }

    this.exists = function(key){
        return this.collection[key] !== undefined;
    }
}

iframed.js:

function foo(window, socketKey) {
    if (window.socketsCollection.exists(socketKey)) return;

    var newSocketData = {
        url: "wss://echo.websocket.org/",
        onopen: function(e, key, ws) {
            console.log(key + ' is OPEN', ws.readyState)
            ws.send('Hello socket ' + key);
        },
        onclose: function(e, key, ws) {
            console.log(key + ' is CLOSED', ws.readyState)
        },
        onmessage: function (e, key, ws) {
            console.log(key + ' response: ', e.data);
        }
    };

    window.socketsCollection.add(socketKey, newSocketData);
}

a.html:

<script src="iframed.js"></script>
<script>
    foo.call(window.parent, window.parent, 'A');
</script>

b.html:

<script src="iframed.js"></script>
<script>
    foo.call(window.parent, window.parent, 'B');
</script>
© www.soinside.com 2019 - 2024. All rights reserved.