打破鸿沟:postMessage 怎么完成跨 iframe 页面通讯?

一. 导言

在前端页面开发中,随着咱们的网页越来越杂乱且功用丰富,咱们常常会运用 iframe 元素将其他网页嵌入到当时页面中,以完成页面的划分和模块化。iframe 供给了一种有用的方法来将不同的功用模块或第三方组件集成到主页面中。

但是,随之而来的问题是,当咱们需求完成跨 iframe 页面的通讯时,就会遇到一些挑战。毕竟,iframe 与主页面是分离的文档,它们可能会存在跨域的束缚。这就引出了一个问题:怎么在不同的 iframe 页面之间进行数据传递事情触发函数调用呢?

传统的办法和技能无法直接在不同的 iframe 页面之间进行通讯,因为它们被浏览器的同源战略和跨域的束缚所束缚。

接下来,咱们将一块去探究跨 iframe 页面通讯的解决方案。常见的通讯办法有如窗口音讯传递、postMessage API 和 SharedWorker 等,本文将首要介绍怎么运用 postMessage API 完成跨 iframe 页面通讯。

二. postMessage

在跨 iframe 页面通讯的解决方案中,postMessage API 是一种通用且牢靠的办法,它答应在不同窗口间进行安全的音讯传递。

根本原理

postMessage API 供给了一种经过窗口方针来发送音讯的机制。经过运用 postMessage,咱们能够在不同的 iframe 页面之间传递数据,触发特定事情或调用固定函数。

以下是根本的运用原理过程:

1. 获取方针窗口方针

在发送音讯之前,咱们需求获取方针 iframe 页面的窗口方针。能够运用 window.parentwindow.frames[] 等办法来获取嵌套 iframe 页面的窗口方针。

2. 发送音讯

运用 postMessage API 向方针窗口方针发送音讯。该 API 承受两个参数,第一个参数是要发送的音讯内容,能够是字符串或 JSON 方针;第二个参数是方针窗口的 origin,用于验证方针窗口的来历。

例如,能够运用下面的代码将音讯发送给方针窗口:

const targetWindow = window.frames["targetIframe"].contentWindow;
const message = "Hello, iframe!";
const targetOrigin = "https://example.com";
targetWindow.postMessage(message, targetOrigin);

3. 接纳音讯

在方针窗口中,经过注册 message 事情监听器来接纳音讯。当收到音讯时,能够经过 event.data 来获取传递的音讯内容。

例如,能够运用如下代码来接纳音讯:

window.addEventListener("message", function (event) {
  if (event.origin === "https://example.com") {
    const message = event.data;
    console.log("Received message:", message);
  }
});

由此可见,postMessage API 是一种强壮且灵敏的办法,能够让咱们在不同的 iframe 页面之间完成牢靠和安全的通讯。但需求留意的是,为了确保数据的完整性和安全性,咱们需求在代码中完成恰当的验证和过滤,并对传递的数据进行恰当的处理和解析。

接下来,咱们将介绍更多关于窗口音讯传递的实践技巧,包括数据传递、事情触发和函数调用的详细完成办法。经过这些技巧,咱们将能够更方便地在跨 iframe 页面间完成杂乱的通讯和交互

三. 通讯技巧

在前面咱们介绍了运用 postMessage API 完成 iframe 之间音讯传递的根本原理。接下来,咱们将进一步讨论怎么运用这一办法来完成详细的数据传递、事情触发和函数调用。

1. 数据传递

在跨 iframe 页面间传递数据时,咱们能够在音讯中包含数据内容。这能够是简略的字符串,也能够是杂乱的 JSON 方针。

发送音讯的页面能够将数据作为音讯的内容发送给方针 iframe 页面,而方针页面能够运用 event.data 来获取接纳到的数据。

发送页面:


const targetWindow = window.frames["targetIframe"].contentWindow;
const data = { message: "Hello, iframe!", value: 42 };
const targetOrigin = "https://example.com";
targetWindow.postMessage(data, targetOrigin);

接纳页面:

window.addEventListener("message", function (event) {
  if (event.origin === "https://example.com") {
    const data = event.data;
    console.log("Received data:", data);
  }
});

2. 事情触发

除了传递数据,咱们还能够经过触发特定的事情来完成 iframe 页面之间的通讯。在发送页面中,咱们能够运用 postMessage API 触发自界说的事情,而接纳页面能够监听这些事情并做相应的处理。

发送页面:

const targetWindow = window.frames["targetIframe"].contentWindow;
const eventName = "customEvent";
const eventData = { message: "Hello, iframe!" };
const targetOrigin = "https://example.com";
targetWindow.postMessage({ event: eventName, data: eventData }, targetOrigin);

接纳页面:

window.addEventListener("message", function (event) {
  if (event.origin === "https://example.com") {
    const { event: eventName, data: eventData } = event.data;
    if (eventName === "customEvent") {
      console.log("Received custom event:", eventData);
    }
  }
});

3. 函数调用

除了传递数据和触发事情,咱们还能够经过 postMessage API 完成不同 iframe 页面间的函数调用。在发送页面中,咱们能够将函数名和参数作为音讯内容发送给方针页面。接纳页面能够依据接纳到的音讯内容来履行相应的函数。

发送页面:

const targetWindow = window.frames["targetIframe"].contentWindow;
const methodName = "addNumbers";
const methodArgs = [2, 3];
const targetOrigin = "https://example.com";
targetWindow.postMessage(
  { method: methodName, args: methodArgs },
  targetOrigin
);

接纳页面:

window.addEventListener("message", function (event) {
  if (event.origin === "https://example.com") {
    const { method: methodName, args: methodArgs } = event.data;
    if (methodName === "addNumbers") {
      const result = addNumbers(...methodArgs);
      console.log("Result:", result);
    }
  }
});

这需求确保方针页面中存在所调用的函数,并且函数的履行结果能够传回给发送页面。

经过这些实践技巧,咱们能够在跨 iframe 页面之间完成愈加杂乱和灵敏的通讯。无论是简略的数据传递、事情触发仍是函数调用,咱们能够运用 postMessage API 在不同的 iframe 页面之间完成牢靠、安全和高效的通讯机制。

四. 安全性考虑

确保音讯的安全性和有用性是运用窗口音讯传递时的重要考虑因素。那么怎么确保音讯的安全性与有用性?

1. 验证音讯来历

在接纳音讯的页面中,咱们应该验证音讯的来历是否是可信的。运用 event.origin 特点能够获取音讯的来历,咱们能够经过与预期的来历进行比较来验证音讯的合法性。假如来历不匹配,咱们能够挑选疏忽该音讯或采纳其他恰当的安全措施。

window.addEventListener("message", function (event) {
  if (event.origin !== "https://example.com") {
    // 不是预期的来历,疏忽音讯或采纳其他安全措施
    return;
  }
  // 履行音讯处理逻辑
});

2. 束缚音讯处理规模

咱们能够束缚音讯的处理规模,以确保音讯只在预定的接纳页面中进行处理。在接音讯的页面中,能够经过判别窗口方针的来历、位置或其他特点来验证它是否是预期的收页面。假如验证失利咱们能够挑选疏忽音讯或采纳其他恰当的安全措施。

// 判别是否在预期的接纳页面中处理音讯
if (window.location.href !== "https://example.com/receive.html") {
  // 疏忽音讯或采纳其他安全措施
  return;
}

3. 加密音讯内容

对于敏感数据,咱们能够在发送音讯时进行加密,以确保数据的机密性。能够运用加密算法(如 AES、RSA 等)对音讯内容进行加密,发送方和接纳方之间同享密钥来进行解密。这样能够避免数据在传输过程中被歹意篡改或盗取。

4. 过滤和验证音讯内容

在接纳的页面中,咱们应该对音讯内容进行过滤和验证,以确保接纳到的数据的完整性和有用性。能够运用合适的数据验证和解析办法(比方 JSON 解析器)来处理数据,以避免因为歹意数据导致的安全漏洞(如 XSS 进犯)。

window.addEventListener("message", function (event) {
  if (event.origin === "https://example.com") {
    const data = event.data;
    // 进行数据验证和解析,确保数据的有用性和完整性
    if (isValidData(data)) {
      // 履行音讯处理逻辑
    }
  }
});

综上所述,确保音讯的安全性和有用性需求在代码中施行相应的安全措施。经过验证音讯来历、束缚音讯处理规模、加密敏感数据、过滤和验证音讯内容以及界说安全通讯战略,咱们能够确保窗口音讯传递的安全性,并避免潜在的安全漏洞。

五. 运用场景

窗口音讯传递适用于同源或跨域的 iframe 页面通讯。下面是不同场景的示例:

1. 同源 iframe 页面通讯

假如你的运用中存在同源的 iframe 页面,它们拥有相同的协议、主机和端口,那么你能够轻松地运用窗口音讯传递完成它们之间的通讯。这种情况下,音讯能够直接经过 postMessage API 在不同的 iframe 页面之间传递。

// 发送页面 - 同源 iframe 页面通讯
const targetIframe = document.getElementById("targetIframe").contentWindow;
const message = "Hello, iframe!";
targetIframe.postMessage(message, "*");
// 接纳页面 - 同源 iframe 页面通讯
window.addEventListener("message", function (event) {
  const message = event.data;
  console.log("Received message:", message);
});

2. 跨域 iframe 页面通讯

假如你的运用中存在跨域的 iframe 页面,它们拥有不同的协议、主机或端口,那么你需求在通讯时处理跨域安全性束缚。在发送音讯时,你需求指定接纳音讯的窗口的 origin(来历),接纳方需求验证音讯的来历是否匹配预期的安全来历。

// 发送页面 - 跨域 iframe 页面通讯
const targetIframe = document.getElementById("targetIframe").contentWindow;
const message = "Hello, iframe!";
const targetOrigin = "https://example.com";
targetIframe.postMessage(message, targetOrigin);
// 接纳页面 - 跨域 iframe 页面通讯
window.addEventListener("message", function (event) {
  if (event.origin === "https://example.com") {
    const message = event.data;
    console.log("Received message:", message);
  }
});

在这两种场景下,窗口音讯传递供给了一种简略且有用的方法来完成同源或跨域的 iframe 页面通讯。经过 postMessage API,你能够发送各种类型的数据、触发自界说事情和履行函数调用,完成更杂乱的通讯需求。请留意,在跨域通讯中要特别留意安全性,并进行恰当的音讯验证和束缚。

六. 安全性确保

在上文中,已经提及到了一些通讯时候的安全性考虑事项,包括:验证音讯来历、束缚音讯处理规模、加密音讯内容等等,下面咱们结合上面的的一些考虑总结一下安全性确保的最佳实践。

1. 域名白名单验证

在父页面和子页面之间进行跨域通讯时,能够经过验证音讯的来历域名,只承受来自特定域名的音讯。这样能够避免歹意注入和进犯者假充其他域名发送音讯。

示例代码:

var allowedDomains = ["http://example.com"];
window.addEventListener("message", function (event) {
  if (allowedDomains.includes(event.origin)) {
    console.log(event.data);
  }
});

在这个示例中,allowedDomains 数组中列出了被答应的域名。在监听 message 事情时,只要当事情的 origin 特点在白名单中时,才处理接纳到的音讯。

2. 装备正确的 targetOrigin 参数

在运用 postMessage 发送音讯时,应尽量清晰指定方针源(targetOrigin 参数),以避免音讯被发送到不受信赖的页面。

示例代码:

var iframe = document.getElementById("child").contentWindow;
iframe.postMessage("Hello from parent", "http://example.com");

在这个示例中,将音讯发送给子页面时,将方针源指定为 http://example.com,即只答应该域名下的页面接纳到音讯。

3. 音讯内容验证

在接纳到音讯后,对音讯内容进行验证,确保只处理合法的音讯。能够对音讯的格式、内容进行验证,避免歹意的脚本注入或其他进犯。

示例代码:

window.addEventListener("message", function (event) {
  var message = event.data;
  if (typeof message === "string" && message.startsWith("Hello")) {
    console.log(message);
  } else {
    // 回绝处理不合法的音讯
  }
});

在这个示例中,只要当接纳到的音讯是以 “Hello” 最初的字符串时,才会处理该音讯,否则会回绝处理。

4. 阻挠不必要的子页面间通讯

束缚不同的子页面之间的通讯,只答应父页面与特定的子页面进行通讯。这能够经过装备 X-Frame-Options 和 Content Security Policy(CSP)等安全头来完成。这些安全头能够避免将页面嵌入到其他域下的 iframe 中,然后减少歹意注入和进犯的危险。

示例代码(经过设置 X-Frame-Options):

X-Frame-Options: SAMEORIGIN

在这个示例中,经过设置 X-Frame-OptionsSAMEORIGIN,束缚只答应当时页面在相同域名下的 iframe 中进行嵌入,避免在其他域下的 iframe 中进行嵌入。

综上所述,经过域名白名单验证、正确装备方针源参数、音讯内容验证和阻挠不必要的子页面间通讯等措施,能够有用地确保跨 iframe 页面通讯的安全性,避免歹意注入和进犯。

总结

在本文中,咱们详细分析了经过 postMessage API 跨 iframe 页面通讯的完成办法和技能。无论是同域跨 iframe 通讯,仍是跨域跨 iframe 通讯,以上都供给了常用的解决方案和示例代码。

经过 postMessage API,咱们能够完成 iframe 之间的数据传递、事情处理和同享资源。不论是在单页面运用中,仍是在多个独立页面之间,跨 iframe 页面通讯都能够为咱们带来愈加灵敏、高效的交互和协作方法。

但是,在实践中,咱们也需求留意安全性和功能方面的考虑。在跨域通讯中,要确保信赖的源站点,并采纳恰当的安全措施,避免歹意注入和进犯。一起,还要控制跨 iframe 通讯的频率和数据量以确保功能和用户体会。

总的来说,跨 iframe 页面通讯是一项非常有价值的技能,能够解决前端运用中的许多实际问题。咱们应该依据实际需求挑选合适的通讯办法,并加以灵敏运用。经过合理的设计和技能完成,咱们能够打破页面鸿沟,创造出愈加强壮、赋有交互性的前端运用。

参考资料