javascript - Google Chrome: Accessing window.opener for target="_blank" link after rel="noopener" is the new default
问题描述
I just learned about the rel="noopener"
attribute, which makes the opened windows unaware of their opener. I played with it a bit and got window.opener === null
all the time, until I found out that it's now the new default in all modern browsers.
Now, I'd like to actually read the window.opener
property to see how it works:
<!-- http://opener-from.test/ -->
<a href="http://opener-to.test/" target="_blank">no rel</a>
<a href="http://opener-to.test/" target="_blank" rel="opener">rel="opener"</a>
<a href="http://opener-to.test/" target="_blank" rel="noopener">rel="noopener"</a>
<!-- http://opener-to.test/ -->
<script>
console.log(window.opener);
</script>
The no rel
and rel="noopener"
links just make the destination get window.opener === null
. As for the rel="opener"
, it works great it Firefox and Safari, but in Google Chrome I'm getting the error:
Uncaught DOMException: Blocked a frame with origin "http://opener-to.test" from accessing a cross-origin frame.
I tested it in Chrome 91. How can I access the window.opener
in the context of target="_blank"
in Google Chrome?
解决方案
这与默认的无关,rel
与跨域访问有关。来自MDN 的文档opener
:
如果打开器与当前页面不在同一源上,则打开器对象的功能受到限制。例如,窗口对象上的变量和函数是不可访问的。但是,打开器窗口的导航是可能的,这意味着打开的页面可以在原始选项卡或窗口中打开一个 URL。
(我的重点)
console.log(window.opener)
将尝试访问window.opener
.
可以在rel="opener"
开启程序中进行导航,但不能访问该窗口公开的全局变量(包括函数)。它还可以postMessage
用来与开启者窗口对话。
如果您只想查看是否可以访问 opener,请console.log(window.opener === null)
改为查看它是true
(您无权访问)还是false
(您的访问权限有限)。
但是,即使使用rel="opener"
,它也是有限的访问权限,如上面的 MDN 引用所示。您无法获得对window.opener
跨域的完全访问权限(仅限同源)。
这种只允许有限访问对象内容的能力不仅仅是浏览器可以做到的魔法,您可以通过以下方式在 JavaScript 本身中做到这一点Proxy
:
const realOpenerWindow = {
x: 42,
};
const opener = new Proxy(realOpenerWindow, {
get(target, property, receiver) {
if (allow) {
return Reflect.get(target, property, receiver);
}
throw new Error(`Access is disallowed`);
}
})
let allow = true;
console.log(opener === null); // false
console.log(opener.x); // 42
allow = false;
console.log(opener === null); // false
console.log(opener.x); // Throws error
关于为什么 Chrome 会出现错误,但 Firefox 等非 Chromium 浏览器不会:不同的控制台实现方式不同。显然,Firefox 的控制台是为了向您展示它允许向您展示的内容,但 Chrome 只是应用其通常的对象处理并触发访问错误。
推荐阅读
- amazon-web-services - AWS RDS 无需重启即可更新 SSL/TLS 证书
- mysql - Docker-compose up 在第一次运行时抛出错误,在第二次运行后运行正常
- .htaccess - htaccess:如何用特殊字符替换字符串?
- reactjs - 如何使用 firestoreConnect 检查数据是否已到达?
- python - Matplotlib:将 axhline 添加到 Figure 对象中的子图
- unit-testing - 如何在 go 中实现 CLI 命令的单元测试
- python - 是否可以在 Google Colab 中导入一个 python 文件,该文件本身会导入一个 GitHub 存储库来运行?
- python - tf.dataset 如何与 keras.conv1D 交互?
- python-3.x - ImportError:无法从“类型”导入名称“DictType”
- node.js - 如何将 URL 中的数组作为参数传递给 Promise.all