Redirect a Popup and Post Message

放肆的年华 提交于 2019-12-10 15:42:11

问题


I am stuck in a problem where i have to redirect from a popup window to a different domain and post a message to it. Here is the scenario :-

  1. User opens a new popup window which stays in same domain.(ex: http://doamin_one.com)
  2. User fills the form in the popup window and clicks submit. This should redirect the window to http://doamin_two.com and domain_two.com should receive form data via post message.

I am able to receive messages if i open fresh popup and do post message but not in the case of redirection. Here is my code:

http://domain_one.com -

   function redirect(formData,popup) {
     //popup=window ref object
     popup.location.href="http://domain_two.com"
     popup.postMessage(JSON.stringify(formData),
          "http://domain_two.com");
}

http://domain_two.com -

window.addEventListener("message", receiveMessage, false);
function receiveMessage(event)
{
 if (event.origin !== "http://domain_one.com")
      return;
 let data=event.data;
 //....
}

回答1:


One issue with the code at the question is that .postMessage() is called immediately following setting a new .location.href at popup without waiting for the load event of window at

 popup.location.href="http://domain_two.com"
 popup.postMessage(JSON.stringify(formData),
      "http://domain_two.com");

To achieve the expected result you can control the process from the original window ('index.html'). Each window.name is set to a unique value. When the <form> is submitted at "http://domain_one.com" the resulting FormData can be converted to an ArrayBuffer and transferred to index.html, then popup (a.html) location.href is set to "http://domain_two.com". At load event of b.html .postMessage() the name of the window to index.html. Then the FormData is passed to .postMessage() where b.html gets the FormData that was originally submitted at b.html.

(The origin checks might need to be adjusted at the below code. The code was tested at plnkr, where simulation of cross-domain messaging is not 1:1, though should provide a pattern for how to accomplish the requirement).

index.html (opener)

<!DOCTYPE html>
<html>
<head>
</head>
<body>
  <script>
    // open `popup`
    const popup = window.open('a.html'); 
    // create random values to assign to `name` at `a.html` and `b.html`
    const [firstName, lastName] = [...Array(2)].map(_ => new Uint32Array(16));
    [firstName, lastName].forEach(buffer => window.crypto.getRandomValues(buffer));
    const [decoder, encoder] = [new TextDecoder(), new TextEncoder()];
    const [first, last] = [firstName, lastName].map(buffer => decoder.decode(buffer));
    // set `name` of `popup` (`a.html`) to `first`
    popup.name = first;
    let data;
    window.addEventListener("message", e => {
      // check `name` of `source` 
      if (e.source.name === first) {
        console.log(e.source.name);    
        // store `formData`        
        data = decoder.decode(e.data);
        console.log(e, JSON.parse(decoder.decode(e.data)));
        // set `name` of `popup` to `last`
        popup.name = last;
        // redirect `popup` to `b.html`
        popup.location.href = "b.html";
      }
      // check if `name` of `source` (`b.html`) is `last` 
      if (e.source.name === last) {
        // encode the stored `formData`
        let curr = encoder.encode(data);
        console.log(e.source.name, e.data);
        // transfer `formData` to `b.html`
        e.source.postMessage(curr.buffer, e.source.location.href, [curr.buffer]);
        // data = void 0;
      }
    })
  </script>
</body>
</html>

a.html (popup, "http://domain_one.com")

<!DOCTYPE html>
<html>
<head>
</head>
<body>
  a
  <form>
    <input name="input">
    <input type="submit">
  </form>
  <script>
    document.forms[0].onsubmit = e => {
      // prevent default `form` submission
      e.preventDefault();
      // pass `form` to `FormData` 
      const formData = new FormData(e.target);
      // encode `formData` as a `Uint8Array`
      const encoded = new TextEncoder().encode(JSON.stringify([...formData.entries()]));
      console.log(encoded);
      // transfer `encoded` to `opener` (`index.html`)
      opener.postMessage(encoded.buffer, opener.location.href, [encoded.buffer]);
    }
  </script>
</body>
</html>

b.html (popup, "http://domain_two.com")

<!DOCTYPE html>
<html>
<head>
</head>
<body>
  b
  <script>
    const decoder = new TextDecoder();
    let data;
    window.addEventListener("message", receiveMessage, false);

    function receiveMessage(event) {
      // check `origin` of `event`
      if (event.origin !== opener.location.origin)
        return;
      console.log(event);
      // process `formData` from `popup`
      data = JSON.parse(decoder.decode(event.data));
      // do stuff with `formData`
      p.textContent = JSON.stringify(data, null, 2);
    }
    // wait for `load` event to be dispatched before posting message to `opener`
    onload = () => {
      opener.postMessage("ok", opener.location.href);
    }
  </script>
  <pre id="p"></pre>
</body>
</html>

plnkr




回答2:


You can pass the form data to "http://domain_two.com" using query string parameters then parse the query string of location.href at load event of the second domain

popup.location.href = `http://domain_two.com?${new URLSearchParams(formData.entries()).toString()}`


来源:https://stackoverflow.com/questions/54509181/redirect-a-popup-and-post-message

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!