【问题标题】:Redirect a Popup and Post Message重定向弹出窗口并发布消息
【发布时间】:2019-06-27 18:47:11
【问题描述】:

我遇到了一个问题,我必须从弹出窗口重定向到另一个域并向其发布消息。 这是场景:-

  1. 用户打开一个新的弹出窗口,该窗口位于同一域中。(例如:http://doamin_one.com
  2. 用户在弹出窗口中填写表格并点击提交。这应该将窗口重定向到http://doamin_two.com,并且 domain_two.com 应该通过 post 消息接收表单数据。

如果我打开新的弹出窗口并发布消息,我能够接收消息,但在重定向的情况下则不行。这是我的代码:

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;
 //....
}

【问题讨论】:

    标签: javascript post popup window postmessage


    【解决方案1】:

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

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

    【讨论】:

    • 表单数据可以变得非常大,数据传输必须是安全的。有没有其他办法?
    • @JSGeek 您能否在问题中包含"http://domain_two.com" 的代码? postMessage()window 加载之前被立即调用。请求也是跨域的。
    • 我已经用代码更新了我的问题。使用 setTimeout 来发布消息也有帮助。
    • 如何知道"http://domain_two.com" 何时加载? popup.postMessage(JSON.stringify(formData), "http://domain_two.com")popup.location.href="http://domain_two.com" 之后在问题代码处立即调用。
    • 你有什么推荐
    【解决方案2】:

    问题中代码的一个问题是,在popup 设置新的.location.href 后立即调用.postMessage(),而无需等待windowload 事件

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

    为了达到预期的结果,您可以从原始window('index.html')控制该过程。每个window.name 都设置为唯一值。当<form>"http://domain_one.com" 提交时,生成的FormData 可以转换为ArrayBuffer 并转移到index.html,然后popup (a.html) location.href 设置为"http://domain_two.com"。在b.html.postMessage()namewindowindex.htmlload 事件。然后将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 (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

    【讨论】:

    • 很确定这种方式不会跨域工作,因为一旦你点击“opener”调用,你就会得到跨域框架异常。
    猜你喜欢
    • 2011-06-30
    • 2023-04-10
    • 1970-01-01
    • 1970-01-01
    • 2023-01-16
    • 2014-10-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多