I am trying to use postmessage to communicate between a parent window, and a child iframe, both of which are located on different domains.
For the parent window I have the code
var otherFrame = document.getElementById("otherFrame").contentWindow;
otherFrame.postMessage("sent'", "https://iframeURL.net");
For the child iframe I have the code
function receiveMessage(event){
if (event.origin !== "https://parentURL.com")
return;
console.log((event.orgin + " " + event.message));
};
window.addEventListener("message", receiveMessage, false);
However, whenever the code is executed, the console logs both event.origin and event.message as undefined, even though the receiveMessage method is called.
Any help would be greatly appreciated!
Ok so the solution to this was very dumb. I misspelled 'origin' in my code, and realized that the correct syntax is event.data, and not event.message
Related
I have a webpage at url https://parent.com and it has an iframe injected into it with source https://iframe.com. Iframe has a global variable defined called iframe_variable. I want to access the iframe_variable from parent document.
I know browsers don't allow cross origin communication and they provide a postMessage API to do it securely.
Constraint: I do not have access to any of parent or iframe code.
On Browser console, I somehow want to access iframe_variable
I have tried the following:
Get reference of iframe first.
var iframe = document.getElementsByTagName('iframe')[0]; // There is only one iframe on document
Create a listener for message event posted from parent window.
var iframeListener = function(e) {
console.log("Got message from parent");
e.source.postMessage(JSON.stringify({'IFRAME_VARIABLE': window.IFRAME_VARIABLE}));
}
Create a listener for parent window to accept 'message' posted from iframe.
parentListener = function(e) {
console.log('Got message from iframe');
var data = JSON.parse(e.data);
window.VARIABLE = data.IFRAME_VARIABLE;
}
Attach parent_listener to message event.
window.addEventListener('message', parentListener, false);
Now if i try to post a message to iframe from parent as follows:
iframe.contentWindow.postMessage('test message', '*')
It doesn't trigger 'iframeListener'. The reason is because it is not registered against the message event in iframe.
I don't think I can even do that from the browser console when I am on parent.com as any attempt to do iframe.contentWindow.addEventListener will result in an error as it will be an attempt to access a different domain.
Is there a workaround that? Is there anything that I am missing in my understanding and research.
P.S: I have not written the origin checks for simplicity. I know I must check for the origin a message is posted from. Not doing that leaves a huge security hole.
I'm having issue passing HTMLIFrameElement object from parent site to iframe (located on a different domain) using postMessage method.
This is my code that I already tried:
var frame = document.getElementById('myHTMLIFrameElement');
frame = JSON.parse(JSON.stringify(frame));
event.source.postMessage(frame, "*");
Unfortunately, JSON.parse/JSON.stringify does not seem to be the right way of handling HTMLIFrameElement object. Can you please advise how to pass through HTMLIFrameElement object correctly?
Parsing DOM elements as JSON does not do anything useful as far as I know.
Since postMessage() is part of the window object, you could try using the window object of the frame, which is found under the contentWindow property of the iframe.
So you could try something like:
var frame = document.getElementById('myHTMLIFrameElement');
frame.contentWindow.postMessage( "stuffYouWantToSendToTheIframe", '*' );
And then in the script inside the iframe:
window.addEventListener('message', function( event ) {
// handle message
});
...but I do control part of the javascript inside the second domain (which integrates the iframe).
So, what I need is some workaround my problem. We have example2.com (this one holds the iframe) and example.com (this one is the original, within the iframe). Inside the iframe the user clicks a button that executes parent.redirectUser() and although I have that function defined in example2.com it fails to execute because it points the function as forbidden to access from within the iframe. Considering I can control the javascript in example2.com, is there any other way to workaround this situation? Thank you very much for your help...
Yes, you can do it.
You can use messages technique,
send message from child(example2.com):
parent.postMessage("Ok", "example.com");
in parent(example.com) you must add the following code:
//add eventlistener for message event
if (window.addEventListener) {
window.addEventListener("message", listener);
} else {
// IE8
window.attachEvent("onmessage", listener);
}
function listener(event) {
//check the message trust or not?
if (event.data == "Ok") {
//from parent you can call function, but function must be placed in global scope
redirectUser();
}
}
I'm trying to get postMessage() to work to communicate between an iframe and my main website. However using the exact syntax given in the example code on MDN, I am being presented with a nice Undefined is not a function error. I've tried several things, such as initializing the iframe inside Javascript and appending it to my page, but that left me with the same error. Same for have seperate selectors to select my iframe.
I have the following Javascript code:
<script type="text/javascript">
$(document).ready(function() {
$('.editor').postMessage("A", "domain here");
});
function receiveMessage(event)
{
if (event.origin !== "domain here")
return;
// Do something
}
window.addEventListener("message", receiveMessage, false);
</script>
The script above tries to send a message to my iframe on the page, which looks like:
<iframe src="domain here/frameListener.html" class="editor"></iframe>
It then has a function receiveMessage to catch any messages being send as a response to the main webpage. Last but not least, I've tried the answers given in this question: But that did not fix my problem. It is therefore not a duplicate.
How can I get rid of this error message?
postMessage is not a jQuery function so you need to get the actual window DOM element and call it on that:
$('.editor').get(0).contentWindow.postMessage("A", "domain here");
Furthermore, you need to access the contentWindow property of the iframe. Here is an excerpt from the MDN docs:
otherWindow.postMessage(message, targetOrigin, [transfer]);
otherWindow
A reference to another window; such a reference may be
obtained, for example, using the contentWindow property of an iframe
element, the object returned by window.open, or by named or numeric
index on window.frames.
I have been stuck on this for hours.
I have a.html on http://example.com that contains an iframe with src to
b.html on http://subdomain.example.com. a.html has some JS code
to postMessage to the iframe.
The code to postMessage is simple:
iframe_window.postMessage('message', iframe_element.src)
But this way, Chrome throws an error:
Unable to post message to http://subdomain.example.com. Recipient has origin null.
I have also tried:
iframe_window.postMessage('message', 'http://subdomain.example.com')
But NO LUCK!
This is the ONLY WAY it works:
iframe_window.postMessage('message', '*')
But I have heard '*' is not good to use.
No problems in Firefox.
It looks like this might be an issue with the child iframe not being loaded at the time the signal is sent, thus iframe.src doesn't have the proper value.
I did some testing and got the same error as you, but when I wrapped the postMessage call in a setTimeout and waited 100ms then there was no error, which tells me that this is an initialisation race condition.
Here's how I implemented a cleaner solution without the setTimeout:
Parent:
window.addEventListener("DOMContentLoaded", function() {
var iframe = document.querySelector("iframe")
, _window = iframe.contentWindow
window.addEventListener("message", function(e) {
// wait for child to signal that it's loaded.
if ( e.data === "loaded" && e.origin === iframe.src.split("/").splice(0, 3).join("/")) {
// send the child a message.
_window.postMessage("Test", iframe.src)
}
})
}, false)
Child:
window.addEventListener("DOMContentLoaded", function() {
// signal the parent that we're loaded.
window.parent.postMessage("loaded", "*")
// listen for messages from the parent.
window.addEventListener("message", function(e) {
var message = document.createElement("h1")
message.innerHTML = e.data
document.body.appendChild(message)
}, false)
}, false)
This is a simple solution in which the child will signal to anyone that it's loaded (using "*", which is okay, because nothing sensitive is being sent.) The parent listens for a loaded event and checks that it's the child that it's interested in that's emitting it.
The parent then sends a message to the child, which is ready to receive it. When the child gets the message it puts the data in an <h1> and appends that to the <body>.
I tested this in Chrome with actual subdomains and this solution worked for me.
A shorter solution is to wrap the postMessage inside iframe_element.onload function.