重定向弹出窗口并发送消息

8
我陷入了一个问题中,需要从弹出窗口重定向到不同的域并向其发送消息。以下是情况:
1.用户打开一个新的弹出窗口,该窗口停留在同一域中。(例如:http://doamin_one.com
2.用户在弹出窗口中填写表单并单击提交。这应该将窗口重定向到http://doamin_two.com,并且应通过post消息将表单数据发送给domain_two.com。
我能够接收消息,如果我打开一个全新的弹出窗口并执行post message,但在重定向的情况下不能接收。以下是我的代码: 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;
 //....
}
2个回答

0

您可以使用查询字符串参数将表单数据传递到"http://domain_two.com",然后在第二个域的load事件中解析location.href的查询字符串。

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

我已经更新了我的问题并附上了代码。使用setTimeout来发送post消息也没有帮助。 - JSGeek
你如何知道"http://domain_two.com"已加载完成?在问题的代码中,popup.location.href="http://domain_two.com"之后立即调用popup.postMessage(JSON.stringify(formData),"http://domain_two.com") - guest271314
你有什么推荐? - JSGeek
@JSGeek 你可以尝试使用 StoragehistoryMessageChanneliframe 元素或者 SharedWorkerServiceWorker 进行通信。或者通过将 window.open() 替换为设置 popup .href,与 opener 进行通信。本质上,问题中的代码试图向自身发送 postMessage()。最简单的方法是在新窗口的 load 事件中解析查询字符串。 - guest271314
@JSGeek 请查看以下链接:https://stackoverflow.com/questions/37127985/, https://stackoverflow.com/questions/46461819/, https://dev59.com/LFkT5IYBdhLWcg3wStof, https://stackoverflow.com/q/46337968/, https://stackoverflow.com/questions/33645685/ - guest271314
显示剩余2条评论

0
问题在于该代码中,当在popup设置新的.location.href后,立即调用.postMessage(),而不等待window上的load事件。
 popup.location.href="http://domain_two.com"
 popup.postMessage(JSON.stringify(formData),
      "http://domain_two.com");

为了达到预期的结果,您可以从原始window('index.html')控制过程。每个window.name都设置为唯一值。当在"http://domain_one.com"提交<form>后,生成的FormData可以转换为ArrayBuffer并传输到index.html,然后popupa.html)的location.href设置为"http://domain_two.com"。在b.htmlload事件中,将windowname.postMessage()发送到index.html。然后,FormData被传递给.postMessage(),其中b.html获取最初在b.html提交的FormData
(下面的代码可能需要调整origin检查。该代码已在plnkr上进行了测试,在那里模拟跨域消息传递不是1:1,但应提供如何完成要求的模式)。

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 (弹出窗口, "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")

b.html(弹出窗口"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


很确定这种方式在跨域时不起作用,因为一旦你调用“opener”,就会出现跨源框架异常。 - cakidnyc

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接