I have an application running inside an iframe on a "foreign" page (different domain etc.). To allow some basic communication between the iframe & the parent, I load some script of mine on the parent page and use postMessage
to do some cross document messaging.
Most of the time this communication works as intended, but sometimes I see some errors reported to my error tracking tool and can't figure out why they happen.
Here's some exemplary code:
PluginOnParent.js
// ...
window.addEventListener('message', function(e) {
// Check message origin etc...
if (e.data.type === 'iFrameRequest') {
e.source.postMessage({
type: 'parentResponse',
responseData: someInterestingData
}, e.origin);
}
// ...
}, false);
// ...
AppInsideIFrame.js
// ...
var timeoutId;
try {
if (window.self === window.top) {
// We're not inside an IFrame, don't do anything...
return;
}
} catch (e) {
// Browsers can block access to window.top due to same origin policy.
// See http://stackoverflow.com/a/326076
// If this happens, we are inside an IFrame...
}
function messageHandler(e) {
if (e.data && (e.data.type === 'parentResponse')) {
window.clearTimeout(timeoutId);
window.removeEventListener('message', messageHandler);
// Do some stuff with the sent data
}
}
timeoutId = window.setTimeout(function() {
errorTracking.report('Communication with parent page failed');
window.removeEventListener('message', messageHandler);
}, 500);
window.addEventListener('message', messageHandler, false);
window.parent.postMessage({ type: 'iFrameRequest' }, '*');
// ...
What happens here, when the timeout hits and the error is reported?
Some more info & thoughts of mine:
- I have no control over the parent page myself
- It doesn't seem to be a general "configuration" issue (CORS etc.) since the error happens on the same page where it works most of the time
- We don't support IE < 10 and other "legacy" browser versions at all, so those are no issue here
- My error reporting tool reports a multitude of different browsers amongst which are the latest versions of them (FF 49, Chrome 43 on Android 5, Chrome 53 on Win and Android 6, Mobile Safari 10, ...)
- Therefore it doesn't seem like it's an issue related to specific browsers or versions.
- The timeout of 500 ms is just some magic number I chose which I thought would be completely safe...
The problem appears to be in your PluginOnParent.js, where you are sending your response. Instead of using "e.origin" (which upon inspection in the developer tools was returning "null") -- try using the literal '*', as it states in the following documentation on postMessage usage (in the description for targetOrigin):
https://developer.mozilla.org/en-US/docs/Web/API/Window/postMessage
Also, as a bonus, I just tested this across two different domains and it works as well. I placed Parent.html on one domains web server, and changed the iframe's src to be child.html on a completely different domain, and they communicated together just fine.
Parent.html
Child.html
Hope that helps!
Not certain what the function
errorTracking.report
does when called, though does not appear that an actual error relating tomessage
event occurs?With
duration
set at500
,setTimeout
could be called before amessage
event fires atwindow
.Adjust the
duration
ofsetTimeout
to a greater duration.Alternatively substitute
onerror
handler orwindow.addEventListener
forsetTimeout
For example
to handle any actual errors during communicating between different contexts, or origins.
Use
postMessage
atload
event ofiframe
to communicate withmessage
handlers at parentwindow
.http://plnkr.co/edit/M85MDHF1kPPwTE2E0UGt?p=preview