3

I have a simple HTML5 page with an iframe whose src attribute is initially empty string. The page renders without any JavaScript errors.

The src attribute of iframe element is only set when the window has loaded, so initially an empty iframe loads. The iframe src is being set to a page from another domain.

The problem I am facing is that the postMessage method works without throwing any errors, however the source page is not firing the message event even though it's set up before the iframe page starts loading. I am having the alert messages from iframe page show up, which means the postMessage method did not throw any errors.

Question

What am I missing when subscribing to the message event in source page?

Source page

<!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>

Iframe Page JavaScript that is not throwing any error (i.e. page at 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>
Sunil
  • 18,294
  • 25
  • 99
  • 171
  • You've said you're seeing the alerts from the iframe, but the iframe doesn't include jQuery (and relies on jQuery). It doesn't inherit it from the enclosing page. So if you're seeing the alerts, the above is **not** the full content of the page you're loading in the iframe. – T.J. Crowder Dec 31 '17 at 10:13
  • @T.J.Crowder, The page at www.abcx.com has jquery included. Also, I have mentioned only the script part of the page at www.abcx.com and not the full html markup of it. – Sunil Dec 31 '17 at 10:16
  • Okay. Next time, it would be good to include at least enough of the iframe code that it would work when copied and pasted. – T.J. Crowder Dec 31 '17 at 10:21
  • @T.J.Crowder, I normally would have included, but in this case my iframe page had too much of markup, so I omitted the markup. – Sunil Dec 31 '17 at 10:25

2 Answers2

1

You're hooking up the listener on the wrong window, and using the wrong window to send the message. (This is fairly easy to get wrong. :-) )

In the main window, you want to receive message events on the main window, not the iframe, so:

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

In the iframe, you want to send to window.parent (well, parent), not window:

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

With both of those changes, the message sent by the iframe is received by the main window.

T.J. Crowder
  • 879,024
  • 165
  • 1,615
  • 1,639
  • Ok. Let me try it out. – Sunil Dec 31 '17 at 10:26
  • That worked.Thanks. – Sunil Dec 31 '17 at 10:32
  • Is `parent.window` from iframe page not pointing to iframe.contentWindow? From the way your code worked, it seems it points to main window of source page. – Sunil Dec 31 '17 at 10:47
  • @Sunil: (You mean `parent`, not `parent.window`, though `parent.window` works [as does `parent.window.window` and `parent.window.window.window`] because `parent === parent.window`.) In the iframe, `parent` refers to the window that contains it (your main page in this case). You can't do virtually anything with that window other than call `postMessage` on it (because it's from a different origin). – T.J. Crowder Dec 31 '17 at 10:51
  • Yes, sorry my mistake and now I cannot edit my comment. – Sunil Dec 31 '17 at 10:53
  • @Sunil: No worries, we can just delete all the comments above if you're all set now...? – T.J. Crowder Dec 31 '17 at 10:55
  • Yes, I get it now very well. May be these comments might help some future reader. – Sunil Dec 31 '17 at 10:55
1

I found a similar question here

On the page you're trying to load, it should be using top.postMessage or parent.postMessage

Additionally, you should be attaching the listener to the window, not the iframe (and make sure to filter the origin, or else localhost will throw you a false positive)

This is the version of yours I was playing with:

<!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>

And the target for the 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>
jascotty2
  • 21
  • 2
  • 1
    Thanks. I liked the use of `top` in your answer since then the topmost window can be accessed. – Sunil Dec 31 '17 at 10:52