Как опубликовать сообщение в iFrame?

Я разрабатываю расширение Chrome для использования с моим собственным веб-приложением, обрабатывающим веб-страницы (в том числе междоменные), загруженные в iFrame на главной странице моего приложения. Поэтому я должен отправить сообщение, содержащее URL-адрес обрабатываемой страницы, с моей главной страницы в скрипт содержимого, введенный в цель iFrame, чтобы получить доступ к окну обработанной страницы.

Я пытаюсь реализовать подход, описанный здесь. Ниже приведены основные части всех задействованных файлов:

index.html:

...
<head>
    ...
    <script type="text/javascript" src="base.js"></script>
</head>
<body>
    <div>
        <input type="text" id="page_url">&nbsp;<input type="button" id="get_page" value="Get page">
    </div>
    <iframe id="cross_domain_page" src=""></iframe>
</body>

base.js:

(function() {
    "use strict";
    function pageProcessing() {
        let urlButton = window.document.getElementById("get_page");
        urlButton.addEventListener("click", () => {
            let url = window.document.getElementById("page_url").value;
            window.postMessage(
                {
                    sender: "get_page_button1",
                    message: url
                },
                "*"
            );
            window.postMessage(
                {
                    sender: "get_page_button2",
                    message: url
                },
                "*"
            );
        });
    }
    window.document.addEventListener('readystatechange', () => {
            if (window.document.readyState == 'complete') {
                pageProcessing();
            }
        }
    );
})();

manifest.json:

{
  "manifest_version": 2,
  "name": "GetPage",
  "version": "0.1",
  "content_scripts": [
    { "js": ["main.js"], "matches": ["<all_urls>"] },
    { "js": ["frame.js"], "matches": ["<all_urls>"], "all_frames": true, "match_about_blank": true }
  ],
  "permissions": ["activeTab"]
}

main.js:

(function() {
    "use strict";
    window.isTop = true;
})();

frame.js:

(function() {
    "use strict";
    window.addEventListener("message", (event) => {
        if (event.data &&
            event.data.sender == "get_page_button1") {
            if (window.isTop) {
                alert("Main window alert");
            } else {
                alert("Frame window alert 1");
            }
        }
    });
    if (!window.isTop) {
        window.addEventListener("message", (event) => {
            if (event.data &&
                event.data.sender == "get_page_button2") {
                alert("Frame window alert 2");
            }
        });
    }
})();

Проблема в том, что когда я нажимаю кнопку «get_page», единственное предупреждение, которое я вижу, — это предупреждение в главном окне. Насколько я понимаю, это означает, что сообщение, отправленное из главного окна, не доходит до скрипта контента, внедренного в iFrame.

Что не так с моим скриптом и как исправить проблему?


person Kostiantyn Ivashchenko    schedule 01.05.2020    source источник


Ответы (1)


window.postMessage в вашем веб-приложении отправляет в основной документ window, а не в iframe.

Укажите объект окна iframe:

document.getElementById('cross_domain_page').contentWindow.postMessage(.......)

Кроме того, вы можете переключиться на более безопасный обмен сообщениями externally_connectable.

person wOxxOm    schedule 01.05.2020
comment
Мне кажется странным, что функция, работающая таким образом, называется POSTmessage, потому что она фактически ПОЛУЧАЕТ сообщение для конкретного окна. Соглашения об именах иногда бывают такими странными. )) Но ваше решение работает, большое спасибо, @wOxxOm. - person Kostiantyn Ivashchenko; 01.05.2020
comment
следует ли из вашего ответа, что для отправки сообщения от iFrame обратно в главное окно я должен использовать что-то вроде if (!window.isTop) { ... window.parent.postMessage(...); }? - person Kostiantyn Ivashchenko; 02.05.2020
comment
Будет ли postMessage работать с междоменными фреймами? Я не могу получить доступ к contentWindow моего iframe, который загружает междоменную страницу. - person Hulk; 02.11.2020
comment
postMessage предназначен для работы с фреймами/окнами из разных источников. Задайте новый вопрос с помощью MCVE. - person wOxxOm; 03.11.2020
comment
СПАСИБО @wOxxOm! Потратил на это столько часов! - person Rohan Taneja; 13.03.2021