与 Window.postMessage 的跨域 iframe 通信
🤔 为什么我们需要跨域 iframe 通信?
想象一下,您需要与将用作应用程序一部分的“第三方服务”集成。
你们两家公司都只是初创公司,我们没有种类齐全的工具可以让我们的生活更轻松,所以我们选择iframe
作为首选。我们_必须_整合我们现在拥有的测试版。之后,我们将重构代码并使用边缘技术,正如我们的经理所承诺的(😉)
他们的应用程序(例如)可以显示私人信息,可能是一些实时银行详细信息/运输/交易详细信息,并且只有在用户授权后才能使用。
🤓 还有什么更好的解决方案?
集成的最佳版本(恕我直言)是获得一个包含组件、钩子、实用程序等的反应库,它将为我们做所有事情。例如,查看React Stripe.js 组件。次优 - 采用 Open API(例如Stripe API)并实现我们自己的组件。
🤨 我们要构建什么?
💭 思路总结
作为 Parent 应用程序,我们希望使用一些令牌在iframe
中登录,因此iframe
可以显示相关信息。每 N 分钟(在这种情况下为 5 秒),我们的令牌就会过期,并且iframe
需要请求另一个令牌。作为奖励,我们可以将主题从 dark 更改为 light,这可能发生在双方。
大多数情况下,我会列出仅与iframe
和Web 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
这是一个“特殊”应用程序,您可以用于真实世界的测试,以了解消息在您的应用程序中的工作方式。
🧑 父代码
🔗链接到部署的应用程序
🔗 源代码可用于复制这里
至于 Parent 应用程序,我们肯定会在我们这边渲染iframe
。让我们从它开始:
-
iframeRef 是我们的React.js 引用到 DOM 元素,所以我们以后可以使用它
-
onLoad - 这将发送我的初始令牌
接下来:我们如何发送消息是Window.postMessage
window.postMessage() 方法安全地启用了Window对象之间的跨域通信;例如,在页面和它产生的弹出窗口之间,或者在页面和嵌入其中的 iframe 之间。
const postMessage = (message: Message) => {
iframeRef.current.contentWindow.postMessage(message, CHILD_APP_URL); // OR use '*' to handle all origins
};
进入全屏模式 退出全屏模式
postMessage
将message: Message
作为参数 - 这是我们自己选择并同意 Child 应用程序传递的消息种类:
使用结构化克隆算法对数据进行序列化。这意味着您可以将各种数据对象安全地传递到目标窗口,而无需自己序列化它们。
为了发送实际消息,我们使用iframeRef.current.contentWindow
作为我们的targetWindow
(来自文档),函数的第二个参数是targetOrigin
:
指定要调度的事件的 targetWindow 的来源,或者作为文字字符串“*”
我知道我的targetOrigin
,所以我通过它并建议你不要忽视安全风险。
祖兹 100093 * *
最后但并非最不重要的一点是,我们想听孩子的消息!
安全和过滤:我们只接受我们确定的消息
// 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
。
并且在type
中收听消息有所不同。
🔗 链接
🎨 父应用: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 通信在特定情况下会派上用场,我们完全可以利用双向消息传递来使其更加动态。通过单击示例自行检查。
谢谢阅读!
更多推荐
所有评论(0)