返回

跨域不同标签页打开window.open(),加载成功页面

javascript

在不同的标签页中打开 window.open()

问题

你正在测试一个第三方 SSO 系统,该系统在一个不同的标签页中运行。成功登录后,你可以以 .php 表单运行任何你想要的脚本。你需要登录脚本在浏览器中打开的一个特定标签页中加载成功页面。

假设你在标签页 1 中访问 acme.com,并单击 APP 上的登录。Acme.com 在新窗口中弹出标签页 2 并执行 SSO。你登录并希望运行一个脚本,在标签页 1 中加载已登录页面,并关闭标签页 2。

解决方案

使用 postMessage

postMessage() 方法允许你跨域发送消息,即使窗口来自不同的域。这使我们能够从 SSO 标签页向主应用程序标签页发送消息,并触发成功页面的加载。

步骤:

1. 在 SSO 标签页中:

  • 使用 postMessage() 方法向主应用程序标签页发送一条消息,其中包含成功状态和成功页面的 URL。
  • 例如:
window.opener.postMessage({ success: true, url: 'https://example.com/success' }, '*');

2. 在主应用程序标签页中:

  • 监听 postMessage() 事件。
  • 当收到消息时,加载提供的成功页面。
  • 例如:
window.addEventListener('message', (event) => {
  if (event.data.success) {
    window.location.href = event.data.url;
  }
});

关闭标签页

一旦成功页面加载,你可以使用 window.close() 方法关闭 SSO 标签页。

示例代码

SSO 标签页:

window.opener.postMessage({ success: true, url: 'https://example.com/success' }, '*');
window.close();

主应用程序标签页:

window.addEventListener('message', (event) => {
  if (event.data.success) {
    window.location.href = event.data.url;
  }
});

注意

  • 确保主应用程序标签页和 SSO 标签页来自同一个域,否则 postMessage() 不会起作用。
  • 使用 "*" 作为 postMessage() 的第二个参数,表示消息可以发送到任何窗口。

结论

通过使用 postMessage() 方法,你可以跨域在不同的标签页中打开 window.open(),并加载成功页面。这对于实现第三方 SSO 系统和其他涉及多标签页操作的场景非常有用。

常见问题解答

1. 如果 postMessage() 没有触发主应用程序标签页中的事件,该怎么办?

  • 检查主应用程序标签页是否正在监听 postMessage() 事件。
  • 检查消息传递的源是否与主应用程序标签页的域相匹配。
  • 确保已将 "*" 用作 postMessage() 的第二个参数。

2. 如何关闭 SSO 标签页而不手动调用 window.close()?

  • 在主应用程序标签页中,使用 Window.postMessage() 方法向 SSO 标签页发送一条关闭消息。
  • 在 SSO 标签页中,监听 Window.postMessage() 事件并根据需要关闭标签页。

3. 如何在不同窗口而不是标签页中打开 window.open()?

  • 在 window.open() 的第二个参数中指定 "noopener" 选项。
  • 这将创建一个新的窗口,但不会与主应用程序窗口共享任何会话数据。

4. 如何在 iframe 中使用此方法?

  • postMessage() 方法也可以在 iframe 和其父窗口之间使用。
  • 只需确保 iframe 的源域与父窗口的域匹配即可。

5. 还有其他方法可以在不同的标签页中加载成功页面吗?

  • 除了 postMessage(),你还可以使用 Window.location.replace() 方法或 AJAX 来在不同的标签页中加载页面。