如何防止使用target="_blank"/window.open()打开新窗口/标签时sessionStorage被继承?

15

在一个URL为http://foo.com/的标签页上,我这样设置了一个sessionStorage项-

sessionStorage.bar="hello";

我随后在同一域名下的任何路径上打开一个新窗口 -

window.open("http://foo.com/any/path");

然后在新窗口中,我发现 -

sessionStorage.bar === "hello"

是的。如果我使用带有target="_blank"属性的链接打开新窗口,也会出现完全相同的情况。同样的事情也会发生在打开新标签页而不是新窗口时。还要注意的是,只有在打开新窗口之前设置在sessionStorage上的项目才会出现这种情况。在新窗口打开后,在任一窗口中添加或更改sessionStorage中的任何项目都不会对另一个窗口产生影响。

我认为sessionStorage应该被限定在单个标签页/窗口中,但显然当从另一个窗口打开新的选项卡和窗口时,sessionStorage会扩展到它们。

有没有办法防止这种情况?我可以测试window.opener是否存在来检测这种情况,但如果能够在第一时间防止这种情况,那就更好了。

谢谢!


1
sessionStorage 是会话级别的,因此得名。无论您在哪个选项卡上使用它都没有关系。 - user1932079
1
@JeremyMiller,感谢您的评论,您能否详细说明一下?那么如何定义会话呢?MDN仅表示:“在新标签页或窗口中打开页面将导致启动新会话。” - odedbd
嗯...我可能弄错了。现在正在仔细检查。 - user1932079
1
找到了。它在他们链接的规格中,但是有点长,所以我会发表为答案。 - user1932079
5个回答

4
您可以使用以下方法:
    const a = document.createElement('a');
    a.href = "http://example.com/any/path";
    a.target = '_blank';
    document.body.appendChild(a);
    a.click();
    document.body.removeChild(a);

到目前为止,我测试过的所有浏览器都能完美运行这个程序。 :) - Otziii

4

设置window.open窗口特性参数“noopener”为true,可以防止新的选项卡或窗口从原始窗口继承sessionStorage副本:

window.open('http://example.com', '_blank', 'noopener=true');

参数'noreferrer'同样有效,如果设置了该参数,则浏览器将省略Referer标头,并将noopener设置为true。

Mozilla window.open文档

注意:当使用window.open在同一窗口中打开URL(即当前窗口,目标设置为'_self')时,此参数不是解决方案。尽管重新分配的窗口将没有window.opener值,但由先前URL设置的会话存储可能仍然存在--至少如果新URL具有相同的域。


太棒了!希望它在所有浏览器中都能正常工作...? - Otziii
我只能保证Firefox浏览器的兼容性。当在同一窗口打开URL时,您可以使用以下代码:let j = sessionStorage.length - 1; for (j; j >= 0; j--) { sessionStorage.removeItem(sessionStorage.key(j)); } window.open('http://www.example.com', '_self'); - Dale Thompson
跟进我的上一个评论:这个解决方案在iOS的Safari浏览器上不起作用。 - Otziii

4
根据Webstorage Specification,"当在具有顶级浏览上下文的浏览上下文中创建新文档时,用户代理必须检查该顶级浏览上下文是否具有该文档来源的会话存储区域。如果有,则该区域为该文档分配的会话存储区域。"
所以,我的理解是,如果你关闭选项卡,然后打开一个新选项卡,根据规范,它将成为一个新的“会话”。但是,如果选项卡保持打开状态,然后再打开一个新选项卡,顶级浏览上下文匹配,因此将引用sessionStorage。

谢谢!除了检查window.opener之外,您有什么建议来覆盖或绕过这种行为吗? - odedbd
只有在onLoad时销毁sessionStorage。你的目标是什么? - user1932079
我无法销毁sessionStorage,所以我想通过检查window.opener来解决问题。再次感谢您的帮助和见解! - odedbd
这种“克隆”行为似乎特定于IE - 至少Firefox和Chrome似乎不会从打开的窗口继承sessionStorage,而且这篇文章是我能找到有关sessionStorage继承的唯一内容。我的理解是规范中的那句话,“具有顶级浏览上下文的浏览上下文”指的是iframes。因此,与包含窗口相同起源的iframe会获得相同的sessionStorage - 而且完全相同的sessionStorage,即由一个上下文所做的更改将被另一个上下文看到 - 不像只有IE表现出的“克隆”sessionStorage行为。 - anton.burger
1
它在Chrome 62上克隆成功,但在Firefox 56上不行。 - Jayen
这可能不是真的。 - Eric

2

我通过在打开新窗口时临时移除会话项来解决了这个问题。

sessionStorage.removeItem('bar');
window.open('http://example.com/any/path', '_blank');
sessionStorage.setItem('bar', 'hello');

0

您可以通过为每个窗口使用单独的键(或者如果您有多个键,则为每个键应用一些唯一前缀)来解决继承行为的问题。

这就引出了如何为每个窗口分配/保留唯一键的问题。SessionStorage is not empty when link opened in new tab in Internet Explorer 显示,您可以将每个窗口的名称设置为某个唯一值,该值在重新加载时保留。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接