1、问题描述
前几天又遇到个神奇Bug,公司某系统的页面出现点击按钮没有反应的问题,反馈问题的用户能稳定复现,技术团队无法复现。
浏览器为 Chrome 115
,控制台可见大量 iframe跨域
报错,具体情况如下:
2、问题原因
根据报错找到的异常代码如下:
看到代码注释的日期我着实有点慌
代码异常是 iframe
页面访问父页面时出现了跨域错误。由于系统近半年没有发版,也没有用户反馈相关问题,因此猜测是当年用的跨域方案失效导致异常。iframe 跨域
的解决方案可以参考 阮一峰博客,文章给出了4种方案:
- 修改
document.domain
- 片段识别符(fragment identifier)
- window.name
- 跨文档通信API(Cross-document messaging)
接着在错误代码的文件头部找到了跨域方案相关的代码,这里采用的方案是修改 document.domain
。
随后在 Chrome路线图 中找到了 document.domain改动 的信息。
经过分析确定问题的原因是:Chrome115
禁用 document.domain setter
导致出现 iframe跨域
错误,进而出现点击按钮无反应的问题。
2.1、无法复现的原因
前面说过这个问题在反馈用户的电脑上必现,但开发团队始终无法复现,这其实是 Chrome
灰度发布策略造成的,从 Chrome
团队的沟通会话可以看出端倪。
截图来自: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
浏览器后,不再出现上述问题。也可以使用 Firefox
、Safari
等其他浏览器。这个方案可能会受到标准化以及灰度发布策略的影响,存在不稳定性,属于不稳定但是简单易行的方案。
3.3、修改浏览器设置
经验证,禁用 Origin-keyed agent clusters
特性后可解决该问题,具体操作步骤如下:
- 浏览器地址栏输入
chrome://flags/#origin-agent-cluster-default
- 然后修改
Origin-keyed Agent Clusters by default
选项值为Disabled
这个方案属于稳定且相对简单的方案。
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.postMessage 或 Channel 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
方案,可彻底根治该问题
最后,现在只想跑路,不想再跟这一堆堆陈年老项目搏斗了,有没有啥好的建议?😭