91

It seems like the point of window.postMessage is to allow safe communication between windows/frames hosted on different domains, but it doesn't actually seem to allow that in Chrome.

Here's the scenario:

  1. Embed an <iframe> (with a src on domain B*) in a page on domain A
  2. The <iframe> ends up being mostly a <script> tag, at the end of which's execution...
  3. I call window.postMessage( some_data, page_on_A )

The <iframe> is most definitely in the context of domain B, and I've confirmed that the embedded javascript in that <iframe> executes properly and calls postMessage with the correct values.

I get this error message in Chrome:

Unable to post message to A. Recipient has origin B.

Here's the code that registers a message event listener in the page on A:

window.addEventListener(
  "message",
  function (event) {
    // Do something
  },
  false);

I've also tried calling window.postMessage(some_data, '*'), but all that does is suppress the error.

Am I just missing the point here, is window.postMessage(...) not meant for this? Or am I just doing it horribly wrong?

*Mime-type text/html, which it must remain.

Kevin Montrose
  • 21,105
  • 8
  • 84
  • 134
  • 1
    You are probably aware of this already, but MDC has an excellent rundown on postMessage: https://developer.mozilla.org/en/DOM/window.postMessage For the FF implementation obviously, but maybe there's something there that explains why it doesn't work. – Pekka Aug 11 '10 at 10:41

3 Answers3

80

Here is an example that works on Chrome 5.0.375.125.

The page B (iframe content):

<html>
    <head></head>
    <body>
        <script>
            top.postMessage('hello', 'A');
        </script>
    </body>
</html>

Note the use of top.postMessage or parent.postMessage not window.postMessage here

The page A:

<html>
<head></head>
<body>
    <iframe src="B"></iframe>
    <script>
        window.addEventListener( "message",
          function (e) {
                if(e.origin !== 'B'){ return; } 
                alert(e.data);
          },
          false);
    </script>
</body>
</html>

A and B must be something like http://domain.com

EDIT:

From another question, it looks the domains(A and B here) must have a / for the postMessage to work properly.

Community
  • 1
  • 1
Mic
  • 23,536
  • 8
  • 55
  • 69
  • 3
    When page A checks the origin of the message, the origin will NOT contain a trailing '/'. It does not seem to matter if page B specifies a trailing '/' or not. The other thing to note is that the URLs should be absolute URLs. – Catch22 Feb 24 '12 at 09:45
  • 1
    This answer left me a bit confused and still searching for an answer. http://blog.teamtreehouse.com/cross-domain-messaging-with-postmessage contains a very good explanation of the postMessage. What is important is that the message sender know the domain of the receiver. In the example above, A and B do not have to be the same domains, but B must know exactly what domain is used by A. – Greg Bogumil Apr 08 '15 at 14:31
  • 7
    The question is about cross-domain. The accepted answer is about the same domain. – stackular May 04 '15 at 14:31
  • @stackular, not exactly. A and B can be any domain. That is the main reason of having `postMessage` – Mic May 06 '15 at 07:05
  • @Mic Yes, after reading the docs https://developer.mozilla.org/en-US/docs/Web/API/Window/postMessage, I saw you were correct. – stackular May 06 '15 at 14:40
  • `var targetOriginurl = window.document.referrer; top.`[postMessage](https://developer.mozilla.org/en-US/docs/Web/API/Window/postMessage)`('Message', targetOriginurl+'/A');` to complete my work, for IE used [attachEvent()](http://stackoverflow.com/questions/2657182/correct-usage-of-addeventlistener-attachevent/10896968#10896968) and to get [domain](http://stackoverflow.com/questions/1034621/get-current-url-in-web-browser/20746566#20746566) refered these links – Yash Jan 13 '16 at 14:08
  • 1
    +1. We want to confirm that this solution worked on our case. We have a page that contains an iframe **from different domain**. Please be note that this only work in Chrome browser, as in firefox we need to use **window.parent.postMessage** instead of **top**. Though we don't know if this can be applied to any other browser. – rahmatns Jul 12 '19 at 10:51
24

You should post a message from frame to parent, after loaded.

frame script:

$(document).ready(function() {
    window.parent.postMessage("I'm loaded", "*");
});

And listen it in parent:

function listenMessage(msg) {
    alert(msg);
}

if (window.addEventListener) {
    window.addEventListener("message", listenMessage, false);
} else {
    window.attachEvent("onmessage", listenMessage);
}

Use this link for more info: http://en.wikipedia.org/wiki/Web_Messaging

Golyo
  • 317
  • 3
  • 3
2

Probably you try to send your data from mydomain.com to www.mydomain.com or reverse, NOTE you missed "www". http://mydomain.com and http://www.mydomain.com are different domains to javascript.

Getoriks
  • 21
  • 1
  • 2
    In a project I'm doing, I'm using `file:///` Is it possible to get domain errors when pulling content solely from the local file system? – Jacksonkr Jun 25 '13 at 15:31