Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

filter messages in receiveMessage javascript

Tags:

javascript

I'm establishing cross-domain communication with JS's postMessage method. An embedded iframe is sending the message and the parent window is receiving it. The issue is that even after checking for origin in receiveMessage (which reduced the number of messages received by a large amount), I'm still receiving two messages, one that I'm posting, and another which was written quite some time ago for a different purpose. So, I can't really modify this other (unwanted) message's postMessage method. Is there a way in the postMessage method or receiveMessage, for that matter, which can help in identifying which one is mine? Maybe some extra parameter or configuration I'm missing here?

Code for postMessage (in the embedded iframe):

window.parent.postMessage("Hello world!", "*");

Code for receiveMessage (in the parent window):

    window.addEventListener("message", receiveMessage, false);
    function receiveMessage(e) {
      var reliableHost = "://" + "<%= Site.current_site.internal_admin_host %>";
      var secureHost = "https" + reliableHost;
      var notSecureHost = "http" + reliableHost;
      if (e.origin.indexOf(secureHost) != -1 || e.origin.indexOf(notSecureHost) != -1) {
        var data = e.data;
        console.log(data);
        console.log(e.source);
      // filter the other event
      }
    }
like image 596
Sindhu Shree Avatar asked Oct 26 '25 08:10

Sindhu Shree


2 Answers

Since the data parameter is entirely under your control and can be an object, you can use a convention within the data parameter to ensure you're only handling the messages you care about. Also note that indexOf(...) != -1 may not be quite right, you probably want indexOf(...) == 0 (or startsWith) instead, to avoid matches later in the string.

So on receipt (see *** lines [you have to scroll right with SO's display]):

window.addEventListener("message", receiveMessage, false);
function receiveMessage(e) {
  var reliableHost = "://" + "<%= Site.current_site.internal_admin_host %>";
  var secureHost = "https" + reliableHost;
  var notSecureHost = "http" + reliableHost;
  if ( (e.origin.indexOf(secureHost) == 0 || e.origin.startsWith(notSecureHost) == 0) && // ***
       (e.data && e.data.type === "whatever")                                            // ***
     ) {                                                                                 // ***
    var payload = e.data.payload;                                                        // ***
    console.log(payload);                                                                // ***
    console.log(e.source);
  // filter the other event
  }
}

on sending:

postMessage({type: "whatever", payload: /*...*/});

I always use this mechanism with distinct type values so that different channels of communication with the same overall page/app doing interfere with each other.

like image 87
T.J. Crowder Avatar answered Oct 27 '25 22:10

T.J. Crowder


Yes: instead of passing in a string, e.g. "Hello world!", pass in an object instead, and perform checks against that. You can first check if e.data is typeof object, and then check what properties the object has. You can set any kind of custom properties that allows you to identify the postMessage of interest. For example, the iframe can execute the following line:

window.parent.postMessage({
    source: 'my-custom-app',
    message: 'Hello world!'
}, '*');

And then when receiving the post message, you can simply check if:

  1. The post message payload (i.e. the data parameter) is an object, and
  2. The post message payload contains the key source and its value is my-custom-app

Example code on the parent page:

window.addEventListener("message", receiveMessage, false);

function receiveMessage(e) {
  var reliableHost = "://" + "<%= Site.current_site.internal_admin_host %>";
  var secureHost = "https" + reliableHost;
  var notSecureHost = "http" + reliableHost;

  // Guard clause to catch unwanted messages from other hosts
  if (e.origin.indexOf(secureHost) === -1 && e.origin.indexOf(notSecureHost) === -1)
    return;

  var data = e.data;
  if (typeof data === 'object' && data.source === 'my-custom-app') {
    // Filtered event handling here
  }
}
like image 36
Terry Avatar answered Oct 27 '25 22:10

Terry