I am having trouble catching errors when using window.postMessage().
I want to be able to capture the error I am getting -
"Unable to post message to http://www.that-domain.com. Recipient has origin http://www.this-domain.com
Simple example code ( should error ):
try {
window.postMessage('1','http://www.differentDomain.com');
}
catch (e) {
alert('error');
}
More detailed process flow: I am adding a cross domain iframe to the document with jQuery and then posting to it. This shouldn't error because the target origins should match - they are both set by the proxyDomain variable.
var $iframeProxy = $('<iframe id="myIFrame" src="' + proxyDomain + '"></iframe>').appendTo('body');
window.storageProxy = $iframeProxy[0].contentWindow;
try {
window.storageProxy.postMessage(message, proxyDomain);
}
catch (e) {
alert('error');
}
The try statement allows you to define a block of code to be tested for errors while it is being executed. The catch statement allows you to define a block of code to be executed, if an error occurs in the try block. The JavaScript statements try and catch come in pairs: try { Block of code to try.
The try-catch statement should be used any time you want to hide errors from the user, or any time you want to produce custom errors for your users' benefit. If you haven't figured it out yet, when you execute a try-catch statement, the browser's usual error handling mechanism will be disabled.
Note: catch {} statement executes only after the execution of the try {} statement. Also, one try block can contain one or more catch blocks.
The try statement defines the code block to run (to try). The catch statement defines a code block to handle any error. The finally statement defines a code block to run regardless of the result. The throw statement defines a custom error. Both catch and finally are optional, but you must use one of them.
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!
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."
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)
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With