JavaScript 面试题
目录

请解释 postMessage 的作用和用法。

· 约 5 分钟读完 · 第 73 / 507 章

推荐答案

postMessage() 方法用于实现跨源(cross-origin)通信。它允许不同源(协议、域名、端口号任意不同)的窗口(例如:iframe、新标签页、弹出窗口)之间安全地传递数据。

作用:

  1. 跨源安全通信: 解决浏览器同源策略带来的限制,允许不同源的脚本安全地进行数据交换。
  2. 异步通信: 发送消息后不会阻塞代码执行,接收消息的操作通过事件监听实现,属于异步通信。
  3. 数据传递: 可以传递各种类型的数据,包括字符串、对象、数组等,传递的数据会自动进行序列化和反序列化处理。

用法:

  • otherWindow: 目标窗口的引用,例如 window.frames[0] (iframe),window.open() 返回的窗口对象。
  • message: 要发送的数据,可以是字符串、对象、数组等。
  • targetOrigin: 指定目标窗口的源(协议+域名+端口)。使用 * 表示允许任何源接收消息(不推荐,可能存在安全风险)。 强烈建议指定具体源地址。
  • event.data : 接收到的数据
  • event.origin : 发送消息的源地址

本题详细解读

postMessage() 是 HTML5 引入的一个强大的 API,主要用于解决浏览器同源策略带来的跨域通信问题。同源策略限制了不同源的文档或脚本之间的交互,包括访问 DOM、读取 cookies 或进行 XMLHttpRequest 请求。postMessage() 允许我们绕过这些限制,实现安全可靠的跨域数据传输。

跨域通信的必要性

在 Web 开发中,经常会遇到需要不同源之间进行通信的场景:

  • iframe 嵌入: 当嵌入来自其他域的 iframe 时,父页面和 iframe 之间需要进行数据交换。
  • 弹出窗口: 通过 window.open() 打开的窗口与打开它的窗口之间可能需要相互通信。
  • 多标签页或窗口: 同一个网站的不同标签页或窗口之间也可能需要共享数据。

postMessage() 的工作原理

  1. 发送消息: 使用 otherWindow.postMessage(message, targetOrigin) 发送消息,其中 otherWindow 是目标窗口的引用。发送消息时,浏览器会将其序列化成字符串,并将其发送给目标窗口。

  2. 接收消息: 目标窗口会监听 message 事件。当收到消息时,会触发该事件,并传递一个包含消息数据的 event 对象。

  3. 消息验证: event 对象包含 origin 属性,指示消息的发送源。为了安全起见,接收方必须验证 event.origin 与期望的源地址是否一致,以防止恶意来源的攻击。

  4. 数据处理: 接收方可以通过 event.data 属性获取发送的消息数据。浏览器会自动将数据反序列化成 JavaScript 对象。

targetOrigin 参数的意义

targetOrigin 参数对于安全性至关重要。

  • 如果设置为具体的源地址(例如,'https://example.com'),则只有来自该源的消息才会被目标窗口接收。这提供了额外的安全保障,防止了恶意网站伪造消息。

  • 如果设置为 *,则表示允许来自任何源的消息被接收。但是,强烈不建议使用 *,因为它可能导致安全漏洞。

postMessage() 的优点

  • 安全性: 通过 targetOrigin 参数和事件的 origin 属性,可以有效地控制跨域通信,降低安全风险。

  • 灵活性: 可以传递多种类型的数据,包括字符串、对象和数组。

  • 异步性: 消息发送和接收操作都是异步的,不会阻塞主线程,提高了页面的响应速度。

常见使用场景

  • iframe 通信: 父页面与 iframe 之间传递数据,例如,父页面设置 iframe 的高度,iframe 向父页面发送数据。
  • 弹出窗口通信: 主窗口与弹出窗口之间进行数据交换。
  • 跨域数据共享: 在不同源的页面之间同步数据,例如用户登录状态。
  • 微前端: 在不同子应用之间进行通信和数据传递。

注意事项

  • postMessage() 不保证消息一定会被送达,这取决于浏览器的实现和网络状况。
  • postMessage() 是单向通信,如果需要双向通信,需要双方都监听 message 事件并互相发送消息。
  • 为了避免安全风险,永远要验证 event.origin 和 targetOrigin,并避免使用 * 作为目标源地址。