JavaScript - Try & Catch - Trouble Capturing Window.postMessage() Errors
I would add to matteo-conta
's solution improved security, to prevent fake domains like www.myproduction-website.com.fakedomain.com
from receiving messages:
function getTargetOrigin() {
const domainDev = 'mydev-website.com';
const domainProd = 'myproduction-website.com';
try {
var url = (window.location !== window.parent.location) ? document.referrer : document.location.href;
const domain = url.split('/')[2];
if (domain.endsWith(domainDev) || domain.endsWith(domainProd))
return document.location.protocol + domain;
else return '';
} catch(e) {
return ''
}
}
const targetOrigin = getTargetOrigin();
try{
if (targetOrigin) window.parent.postMessage(${msg}, targetOrigin);
} catch(e) {
window.parent.postMessage(e, '*')
}
I also added posting the error message to any targetOrigin so that you would be able to capture it on your website's end using:
window.addEventListener("message", onResponse, false);
onResponse(res) {
const data = _.get(res, 'data');
if (res.origin === 'iframe-url-goes-here') {
console.log('message from iframe', data)
}
}
Looks like it is outlined in the HTML5 spec that if the domain origins do not match then no error is thrown and it should abort silently.
http://www.whatwg.org/specs/web-apps/current-work/multipage/web-messaging.html#web-messaging
10.4.3 Posting messages - Part #9
"...if the targetOrigin argument is an absolute URL, and the Document of the Window object on which the method was invoked does not have the same origin as targetOrigin, then abort these steps silently."
No way to catch the error, but usually the error happens if the target origin is different, the case is test vs production scenario.
So you can check what is the parent domain and change the target origin accordingly:
function getTargetOrigin()
{
try {
var url = (window.location != window.parent.location) ? document.referrer : document.location.href;
if (url.indexOf('www.myproduction-website.com')!=-1)
return document.location.protocol + '//www.myproduction-website.com'
else //set the alternative target
return document.location.protocol + '//' + url.split('/')[2];
}
catch(e) //falback to production
{
return document.location.protocol + '//www.myproduction-website.com'
}
}
and use it inside the postMessage function:
function postMessage(message){
window.top.postMessage( message,getTargetOrigin());
}
With this solution you can use the same code in multiple server configuration without hard coding the targetOrigin url.
This solution fails if you navigate inside the frame and you recheck the document.referrer, in that case it will contain not the parent url but the previous frame url. In that case consider to use the '*' as targetOrigin url, it's the only working solution to send messages to other domains.
Hope it helps!