🤔 为什么我们需要跨域 iframe 通信?

想象一下,您需要与将用作应用程序一部分的“第三方服务”集成。

你们两家公司都只是初创公司,我们没有种类齐全的工具可以让我们的生活更轻松,所以我们选择iframe作为首选。我们_必须_整合我们现在拥有的测试版。之后,我们将重构代码并使用边缘技术,正如我们的经理所承诺的(😉)

他们的应用程序(例如)可以显示私人信息,可能是一些实时银行详细信息/运输/交易详细信息,并且只有在用户授权后才能使用。

🤓 还有什么更好的解决方案?

集成的最佳版本(恕我直言)是获得一个包含组件、钩子、实用程序等的反应库,它将为我们做所有事情。例如,查看React Stripe.js 组件。次优 - 采用 Open API(例如Stripe API)并实现我们自己的组件。

🤨 我们要构建什么?

💭 思路总结

作为 Parent 应用程序,我们希望使用一些令牌在iframe中登录,因此iframe可以显示相关信息。每 N 分钟(在这种情况下为 5 秒),我们的令牌就会过期,并且iframe需要请求另一个令牌。作为奖励,我们可以将主题从 dark 更改为 light,这可能发生在双方。


大多数情况下,我会列出仅与iframeWeb API部分相关的代码,不会专注于诸如创建应用程序或解释“如何部署到 Vercel”之类的事情。

Parent 和 Child 应用程序将是我们需要的实际实现。对于前端,我们将使用Next.js和Chakra-UI作为组件。我们将在Vercel和Netlify上部署应用程序(真正跨域)。

此外,我会使用Nrwl Nx 的工作空间来拥有 monorepo,从而保持运行/构建过程无缝。

👨u200d💻 代码(如果您不想阅读简介,请跳至此)

🤖 “沟通者”。

🔗https://iframe-communicator.vercel.app

🔗 Github:https://github.com/andriishupta/iframe-communicator

这是一个“特殊”应用程序,您可以用于真实世界的测试,以了解消息在您的应用程序中的工作方式。

iframe-communicator.png

🧑 父代码

🔗链接到部署的应用程序

🔗 源代码可用于复制这里

至于 Parent 应用程序,我们肯定会在我们这边渲染iframe。让我们从它开始:

iframe3.png

  • iframeRef 是我们的React.js 引用到 DOM 元素,所以我们以后可以使用它

  • onLoad - 这将发送我的初始令牌


接下来:我们如何发送消息是Window.postMessage

window.postMessage() 方法安全地启用了Window对象之间的跨域通信;例如,在页面和它产生的弹出窗口之间,或者在页面和嵌入其中的 iframe 之间。

post-message.png

const postMessage = (message: Message) => {
    iframeRef.current.contentWindow.postMessage(message, CHILD_APP_URL); // OR use '*' to handle all origins
};

进入全屏模式 退出全屏模式

postMessagemessage: Message作为参数 - 这是我们自己选择并同意 Child 应用程序传递的消息种类:

使用结构化克隆算法对数据进行序列化。这意味着您可以将各种数据对象安全地传递到目标窗口,而无需自己序列化它们。


为了发送实际消息,我们使用iframeRef.current.contentWindow作为我们的targetWindow(来自文档),函数的第二个参数是targetOrigin:

指定要调度的事件的 targetWindow 的来源,或者作为文字字符串“*”

我知道我的targetOrigin,所以我通过它并建议你不要忽视安全风险。

祖兹 100093 * *

最后但并非最不重要的一点是,我们想听孩子的消息!

listener.png

安全和过滤:我们只接受我们确定的消息

// skip other messages for security reasons and avoid extensions alerts in console
if (event.origin !== CHILD_APP_URL) {
  return;
}

进入全屏模式 退出全屏模式

现在,让我们从 MessageEvent 中获取数据,并根据业务逻辑进行一些检查和操作:

if (message?.type === 'token-expired-from-child') {
  ...
} else if (message?.type === 'theme-from-child') {
  ...
} else {
  //  in case of some random message
}

进入全屏模式 退出全屏模式

*对于更多选项,可以使用 switch/case(谁喜欢)、三元运算符或对象文字来改进此代码。

最后添加一个监听器并返回一个回调来删除,所以当一个组件发生故障时,你导航到另一个页面,你不需要监听iframe

window.addEventListener('message', handler);
return () => window.removeEventListener('message', handler);

进入全屏模式 退出全屏模式

👶子码

🔗链接到部署的应用程序

🔗 源代码可用于复制这里

Child 应用程序的方法是相同的,只是在哪里调用_postMessage_ -window.parent

child-post-message.png


并且在type中收听消息有所不同。

child-listener.png

🔗 链接

🎨 父应用:https://cross-origin-iframe-communication-with-nextjs-parent-app.vercel.app

👨u200d💻 Github:https://github.com/andriishupta/cross-origin-iframe-communication-with-nextjs


🤖 《沟通者》:https://iframe-communicator.vercel.app

👨u200d💻 Github for "The Communicator":https://github.com/andriishupta/cross-origin-iframe-communication-with-nextjs

📝 总结

跨域 iframe 通信在特定情况下会派上用场,我们完全可以利用双向消息传递来使其更加动态。通过单击示例自行检查。

谢谢阅读!

Logo

React社区为您提供最前沿的新闻资讯和知识内容

更多推荐