Событие сообщения JavaScript не запускается

У меня есть простая страница HTML5 с iframe, атрибут src которой изначально является пустой строкой. Страница отображается без ошибок JavaScript.

Атрибут src элемента iframe устанавливается только после загрузки окна, поэтому изначально загружается пустой iframe. Src iframe устанавливается на страницу из другого домена.

Проблема, с которой я столкнулся, заключается в том, что метод postMessage работает без каких-либо ошибок, однако исходная страница не запускает событие message, даже если оно настроено до начала загрузки страницы iframe. У меня появляются предупреждающие сообщения со страницы iframe, что означает, что метод postMessage не вызывал ошибок.

Вопрос

Что мне не хватает при подписке на событие сообщения на исходной странице?

Исходная страница

<!DOCTYPE html>

<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
    <title>Cross domain iframe messaging</title>
    <script  src="https://code.jquery.com/jquery-1.12.4.min.js"  integrity="sha256-ZosEbRLbNQzLpnKIkEdrPv7lOy9C27hHQ+Xp8a4MxAQ=" crossorigin="anonymous"></script>
    <script type="text/javascript">
            var iframec = null;

            window.addEventListener("load", function () {

                iframec = document.getElementById("iframec");

                //set up event listener for iframe object so it can receive message from page shown in iframe
                iframec.contentWindow.addEventListener("message", function (event) {
                    alert("received: " + event.data);
                }, false);

                //load the iframe page but after you have set up to receive messages
                iframec.src = "http://www.abcx.com";
            });
    </script>
</head>
<body>
    <form id="form1">
    <div>
        <h1>Testing iframe messaging in a Cross Domain scenario</h1>
       <p> Trying to send a message to an iframe that comes from a page in another domain. The postMessage method does not throw an error when called from the other domain page, but it's not being received by the page having iframe element in it.</p>
      <div id="divComments"></div>
        <iframe src=""  id="iframec" name="iframec"  style="border:none;margin:0;padding:0;width:100%; "></iframe>
      </div>
    </form>
</body>
</html>

JavaScript страницы iframe, который не вызывает ошибок (т. е. страница с адресом http://www.abcx.com)

<script>

      $( document ).ready(function() {

          alert("loaded the iframe page on another domain. Just before  postMessage");

          window.postMessage("Some message was sent from other domain message", "*");

          alert("loaded the iframe page on another domain. Just after postMessage");
});

</script>

person Sunil    schedule 31.12.2017    source источник
comment
Вы сказали, что видите предупреждения из iframe, но iframe не включает jQuery (и полагается на jQuery). Он не наследует его от закрывающей страницы. Таким образом, если вы видите предупреждения, это значит, что приведенное выше не является полным содержанием страницы, которую вы загружаете в iframe.   -  person T.J. Crowder    schedule 31.12.2017
comment
@ T.J. Crowder, На странице www.abcx.com есть jquery. Кроме того, я упомянул только часть скрипта на странице www.abcx.com, а не полную его разметку в формате html.   -  person Sunil    schedule 31.12.2017
comment
Хорошо. В следующий раз было бы хорошо включить хотя бы достаточно кода iframe, чтобы он работал при копировании и вставке.   -  person T.J. Crowder    schedule 31.12.2017
comment
@ T.J.Crowder, я бы обычно включил, но в этом случае на моей странице iframe было слишком много разметки, поэтому я пропустил разметку.   -  person Sunil    schedule 31.12.2017


Ответы (2)


Вы подключаете слушателя не к тому окну и используете неправильное окно для отправки сообщения. (В этом довольно легко ошибиться. :-))

В главном окне вы хотите получать message события в главном окне, а не в iframe, поэтому:

    window.addEventListener("message", function (event) {
//  ^^^^^^^
        alert("received: " + event.data);
    }, false);

В iframe вы хотите отправить window.parent (ну, parent), а не window:

    parent.postMessage("Some message was sent from other domain message", "*");
//  ^^^^^^

С обоими этими изменениями сообщение, отправленное iframe, принимается главным окном.

person T.J. Crowder    schedule 31.12.2017
comment
В порядке. Дай мне попробовать. - person Sunil; 31.12.2017
comment
Это сработало. Спасибо. - person Sunil; 31.12.2017
comment
parent.window со страницы iframe не указывает на iframe.contentWindow? Судя по тому, как работал ваш код, кажется, что он указывает на главное окно исходной страницы. - person Sunil; 31.12.2017
comment
@Sunil: (Вы имеете в виду parent, а не parent.window, хотя parent.window работает [как parent.window.window и parent.window.window.window], потому что parent === parent.window.) В iframe parent относится к окну, которое его содержит (в данном случае ваша главная страница). С этим окном практически ничего нельзя сделать, кроме как вызвать postMessage (потому что оно из другого источника). - person T.J. Crowder; 31.12.2017
comment
Да, извините за ошибку, и теперь я не могу редактировать свой комментарий. - person Sunil; 31.12.2017
comment
@Sunil: Не беспокойся, мы можем просто удалить все комментарии выше, если все готово ...? - person T.J. Crowder; 31.12.2017
comment
Да, теперь я понимаю это очень хорошо. Возможно, эти комментарии помогут будущему читателю. - person Sunil; 31.12.2017

Я нашел похожий вопрос здесь

На странице, которую вы пытаетесь загрузить, должно использоваться top.postMessage или parent.postMessage

Кроме того, вы должны прикреплять слушателя к window, а не к iframe (и убедитесь, что вы отфильтровали происхождение, иначе localhost выдаст вам ложное срабатывание)

Это твоя версия, с которой я играл:

<!DOCTYPE html>
<html>
<head>
<script  src="https://code.jquery.com/jquery-1.12.4.min.js"  integrity="sha256-ZosEbRLbNQzLpnKIkEdrPv7lOy9C27hHQ+Xp8a4MxAQ=" crossorigin="anonymous"></script>
<script>
        var iframec = null;

        window.addEventListener("load", function () {
            if(!iframec){
                iframec = document.getElementById("iframec");

                //set up event listener for iframe object so it can receive message from page shown in iframe
                window.addEventListener("message", function (event) {
                    if(event.origin == '[your domain here]') alert("received from " + event.origin + ": " + event.data);
                }, false);

                //load the iframe page but after you have set up to receive messages
                iframec.src = "[iframe target url]";
            }
        });
</script>

И цель для iframe:

<!DOCTYPE html>

<html>
<head>
 <script  src="https://code.jquery.com/jquery-1.12.4.min.js"  integrity="sha256-ZosEbRLbNQzLpnKIkEdrPv7lOy9C27hHQ+Xp8a4MxAQ=" crossorigin="anonymous"></script>
 <script>
   $( document ).ready(function() {
     alert('loaded the page. Just before  postMessage');
     top.postMessage("Some message was sent from appsprocure", "*");
     alert("loaded the page. Just after postMessage");
   });
 </script>
</head>
<body><h1>Hello!</h1></body>
</html>
person jascotty2    schedule 31.12.2017
comment
Спасибо. Мне понравилось использование top в вашем ответе, поскольку с этого момента можно получить доступ к самому верхнему окну. - person Sunil; 31.12.2017