首页 > 解决方案 > 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?

标签: javascripthtmlgoogle-chromesame-origin-policywindow.opener

解决方案


这与默认的无关,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 只是应用其通常的对象处理并触发访问错误。


推荐阅读