跳到主要内容

Chrome115 iframe跨域失败

· 阅读需 9 分钟

1、问题描述

前几天又遇到个神奇Bug,公司某系统的页面出现点击按钮没有反应的问题,反馈问题的用户能稳定复现,技术团队无法复现。

浏览器为 Chrome 115,控制台可见大量 iframe跨域 报错,具体情况如下: image.png

2、问题原因

根据报错找到的异常代码如下: image.png

看到代码注释的日期我着实有点慌

代码异常是 iframe 页面访问父页面时出现了跨域错误。由于系统近半年没有发版,也没有用户反馈相关问题,因此猜测是当年用的跨域方案失效导致异常。iframe 跨域 的解决方案可以参考 阮一峰博客,文章给出了4种方案:

  • 修改 document.domain
  • 片段识别符(fragment identifier)
  • window.name
  • 跨文档通信API(Cross-document messaging)

接着在错误代码的文件头部找到了跨域方案相关的代码,这里采用的方案是修改 document.domainimage.png

随后在 Chrome路线图 中找到了 document.domain改动 的信息。 image.png

经过分析确定问题的原因是:Chrome115 禁用 document.domain setter 导致出现 iframe跨域 错误,进而出现点击按钮无反应的问题。

2.1、无法复现的原因

前面说过这个问题在反馈用户的电脑上必现,但开发团队始终无法复现,这其实是 Chrome 灰度发布策略造成的,从 Chrome 团队的沟通会话可以看出端倪。 image.png

截图来自:https://groups.google.com/a/chromium.org/g/blink-dev/c/nrLl0IxSxSI/m/Sm4IH4yNAwAJ
内容如下: Hello all, it's been a while... The bug reports should now be resolved, and we'd like to have another go at this in the M115 milestone. That is: Remain at 50% on beta; starting with 115 ramp up on stable to 1% / 10% / 50% / 100%, every 14d. Let's hope it sticks this time.

可以看出:Chrome115 稳定版禁用 document.domain setter 的改动采用灰度发布,灰度过程分为4个阶段,覆盖率1% / 10% / 50% / 100%,从发布起每隔14天逐步提升。

Chrome115 稳定版在7月12号发布,按上述计划推算,前几天出现问题时该特性的覆盖面约为10%的用户,100%覆盖大概需要42天,即8月底完成全量覆盖。

问题已经基本搞清楚,接下来就是出方案。结合 Chrome博客Edge官方文档 的相关资料,总结了3种程度的解决方案:临时方案、过渡方案、根治方案。方案主要分为2大类:一是继续使用 document.domain 跨域解决方案,二是使用其他跨域解决方案。若要继续使用原来的跨域方案,就需要借助 Origin-keyed agent clusters 特性 实现。

3、临时方案

由于修复缺陷需要经过开发、测试、部署等一系列环节,可能需要花费不少时间,为满足部分用户的紧急使用需求,可以使用临时方案直接在用户侧绕过该问题。

3.1、使用低版本浏览器

Chrome115 才会出现该问题,因此可以使用版本低于115的 Chrome 浏览器绕过该问题。但是要找到安全可信的低版本 Chrome 安装包有一定难度,另外浏览器如果启用了自动升级策略,那么浏览器重启后可能还会出现问题,属于不稳定且实施难度较大的方案

3.2、使用其他浏览器

经测试,用户使用Edge浏览器后,不再出现上述问题。也可以使用 FirefoxSafari 等其他浏览器。这个方案可能会受到标准化以及灰度发布策略的影响,存在不稳定性,属于不稳定但是简单易行的方案

3.3、修改浏览器设置

经验证,禁用 Origin-keyed agent clusters 特性后可解决该问题,具体操作步骤如下:

  • 浏览器地址栏输入 chrome://flags/#origin-agent-cluster-default
  • 然后修改 Origin-keyed Agent Clusters by default 选项值为 Disabled

image.png

这个方案属于稳定且相对简单的方案

4、过渡方案

4.1、设置Origin-Agent-Cluster响应头

在目标文档添加Origin-Agent-Cluster: ?0 响应头可以解决该问题。要注意的是,涉及跨域访问的html资源都需要添加该响应头。例如父页面 A 和子页面 B存在跨域访问,则页面 A 和页面 B 对应的html响应中都需要添加上述响应头。

这个方案只需要修改静态资源服务器配置,为相关静态资源添加响应头,难度和工作量都不大,可快速实施,短期(1年或更久)内具有稳定性。但是 Origin-keyed agent clusters 特性 尚未成为HTML标准,未来可能会面临失效的风险。是短期内比较好的过渡方案,但不是根治问题的方案,未来存在失效的风险

5、根治方案

5.1、使用 Message API

使用 window.postMessageChannel Messaging API 实现iframe跨域访问,替代修改 document.domain 的方案。

这个方案可以彻底解决问题且几乎不用考虑兼容性问题,唯一的缺点是工作量大,需要先梳理出借助 document.domain 进行跨域的代码再进行代码重构,改动太大还可能影响原有的代码逻辑甚至产生新Bug。如果时间允许,这是最佳方案之一

5.2、改为同域

将静态资源部署到同一个域名下,或使用反向代理改造为同域。同域访问则不需要修改 document.domain,可以把相关代码删除。

这个方案可以彻底解决问题且不用考虑兼容性问题,大部分情况下只需要改造部署方式,修改少量代码,难度和工作量较小。也有一些例外的情况,可能难度和工作量很大,甚至无法使用该方案。这个方案比较神奇,可能是最好的,也可能是最差的,还可能用不了,是否采用需要视具体情况决定

6、总结

Chrome115 开始逐步禁用 document.domain setter ,会导致借助修改 document.domain 实现 iframe跨域 的方案失效,预计8月底全部禁用。

解决方案如下:

  • 浏览器禁用 Origin-keyed agent clusters 特性,可用于临时绕过该问题
  • 添加 Origin-Agent-Cluster:?0 响应头,可用于短期内过渡
  • 将静态资源部署到同一个域名下,使跨域变为同域,可彻底根治该问题,部分场景下很省事,但也有例外
  • 推荐使用 Message API 方案替代修改 document.domain 方案,可彻底根治该问题

最后,现在只想跑路,不想再跟这一堆堆陈年老项目搏斗了,有没有啥好的建议?😭