最近项目中有出现如下的现象
回调父级方法失败 closeDialog DOMException: Blocked a frame with origin "https://xxx.test.cn" from accessing a cross-origin frame.
at HTMLButtonElement.<anonymous>
原因是受限于浏览器的同源策略,但又有同一站点但跨源页面之间通信的需求,于是将document.domain 的值设置为其当前域或其当前域的父域来实现同一站点但跨源页面之间的通信,但是浏览器已经不再支持通过修改 document.domain 来绕开同源策略,所以报错了。
背景
Chrome: 于 2022 年 1 月宣布,将从Chrome 115
document.domain开始弃用设置。如果您的网站依赖于通过放宽同源政策,您需要立即采取行动。使用document.domain 设置(document.domain = ...) 不会引发异常。它只会不再产生作用。
Edge:从 Microsoft Edge 版本 115 开始,将忽略使用 JavaScript 修改 document.domain 属性的尝试。 需要使用替代方法(如 postMessage() 或通道消息 API)进行跨源通信
为什么使 document.domain 不可变
某些网站设置为 document.domain 允许同一网站但跨源页面之间的通信。 通过设置 document.domain ,同一站点文档可以更轻松地进行通信。 由于此更改 放宽了同源策略,因此父页可以访问同一站点 iframe 的文档并遍历 DOM 树,反之亦然。
此方法很方便:但这会带来安全风险。
如何知道我的网站是否受到影响?
-
打开
chrome://flags/#origin-agent-cluster-default选择启用 -
在 DevTools 问题面板查看告警
会影响哪些 JavaScript 的 API
JavaScript 的 API 中,如 iframe.contentWindow、 window.parent、window.open 和 window.opener 允许文档间直接相互引用。当两个文档的源不同时,这些引用方式将对 Window 和 Location 对象的访问添加限制
Window
允许以下对 Window 属性的跨源访问:
| 方法 |
|---|
window.blur |
window.close |
window.focus |
window.postMessage |
| 属性 | |
|---|---|
window.closed |
只读。 |
window.frames |
只读。 |
window.length |
只读。 |
window.location |
读/写。 |
window.opener |
只读。 |
window.parent |
只读。 |
window.self |
只读。 |
window.top |
只读。 |
window.window |
只读。 |
某些浏览器允许访问除上述外更多的属性。
Location
允许以下对 Location 属性的跨源访问:
| 方法 |
|---|
location.replace |
| 属性 | |
|---|---|
HTMLAnchorElement.href |
只写。 |
某些浏览器允许访问除上述外更多的属性。
可使用的替代方案
目前,你有两个选项可以替换 document.domain , 在大多数用例中,跨源 postMessage () 或 通道消息 API 可以替换 document.domain
以下是使用 postMessage() 的步骤,而不是 document.domain 用于跨源 DOM 操作。
https://parent.example.com通过postMessage()将消息发送到 iframe,其中包含https://video.example.com要求其修改其自己的 DOM。
// Configure a handler to receive messages from the subframe.
iframe.addEventListener('message', (event) => {
// Reject all messages except from https://video.example.com
if (event.origin !== 'https://video.example.com') return;
// Filter success messages
if (event.data === 'succeeded') {
// DOM manipulation is succeeded
}
});
// Send a message to the subframe at https://video.example.com
iframe.postMessage('Request DOM manipulation', 'https://video.example.com');
https://video.example.com操作其 DOM,并使用postMessage来通知父级其成功。
// Configure a handler to receive messages from the parent frame.
window.addEventListener('message', (event) => {
// Reject all messages except ones from https://parent.example.com
if (event.origin !== 'https://parent.example.com') return;
// Perform requested DOM manipulation on https://video.example.com.
if (event.data === "showTheButton") {
document.getElementById('btnContinue').style.visibility = 'visible';
// Send a success message back to the parent.
event.source.postMessage('succeeded', event.origin);
}
});
如果有充分的理由继续设置 document.domain,则可以在返回HTML文件上增加 Origin-Agent-Cluster: ?0 响应头
Origin-Agent-Cluster: ?0
响应头 Origin-Agent-Cluster 指示浏览器文档是否应由源密钥代理群集处理。 若要详细了解 Origin-Agent-Cluster,请阅读 使用 Origin-Agent-Cluster 标头请求性能隔离