当前位置: 首页 > Web前端 > HTML5

浅谈sessionStorage的“继承”问题

时间:2023-04-05 16:30:04 HTML5

问题重现最近在写bug的过程中发现了一个有趣的事情。我称之为“sessionStorage‘继承’”。我们可以重现这个过程如下:测试1打开一个页面(我们称之为页面),执行sessionStorage.a='a';window.open(window.location.href);//在console中获取b页面,我们调用新打开的页面b页面,然后我们在b页面console中执行sessionStorage//直接这样写是没有问题的,相当于获取了的sessionStorage属性thewindowobject//output{a:"a",length:1}据我了解,一般认为sessionStorage是页面级的,页面之间互不影响。对于上面的例子,我期望的输出应该只有一个长度属性,而不是这种“继承”的表现。这和我的认知不一样,得查一下。在查看文档之前,我们先对这个问题做一个简单的探索和分析。初步分析,我按照自己的认知进行了测试:测试2executesessionStorage.a='a'inpagea;然后复制a页面的url,新建一个标签页打开这个url,执行sessionStorage//输出{length:0}嗯,我的认知也是对的,但是不够全面,缺乏具体场景的补充。然后我进一步探讨了这一点。在测试一的基础上,我继续:测试三在页面a的控制台执行sessionStorage.a='aaaaaaaa';sessionStorage.b='b';executesessionStorageonpageb//output{a:"a",length:1}至此,综合测试1、2、3,我们大概可以得到如下信息:通过window.open(window.location.href)在a页面会有一份a页面当前sessionStorage的独立副本,之后改变a页面的sessionStorage不会影响b页面的sessionStorage;这时候我又想,如果a页面打开的地址不是window.location.href,而是另外一个地址,根据我们的localStorage和cookie了解,这里应该是有域限制的。于是我们继续测试:测试4我们在页面a(不是https://baidu.com)打开另一个域的地址,得到页面cwindow.open('https://baidu.com');//get在c页面,我们查看了c页面的sessionStorage,发现a页面的sessionStorage没有任何值。嗯,这和我们的认知一样,这种“继承”只发生在同一个领域。所以,综上所述,我们可以得到如下信息:在a页面通过window.open()打开同一个域地址得到的b页面,b页面将拥有a页面当前sessionStorage的独立副本。影响。大概就是这个结论了,那我们去查一下文档,看看有没有文档提到这个结论。文档支持经过一番查找,通过这个问题how-to-prevent-sessionstorage-being-inherited-when-using-target-blank-window的回答找到了相应的文档说明。当在具有顶级浏览上下文的浏览上下文中创建新文档时,用户代理必须检查该顶级浏览上下文是否具有该文档来源的会话存储区域。如果是,那么就是文档分配的会话存储区域。如果没有,则必须为该文档的来源创建一个新的存储区域,然后就是该文档的分配会话存储区域。Document的分配存储区域在Document的生命周期内不会改变。这是一个html标准文档(我理解这应该是浏览器厂商的实现规范),有两个概念需要说明一下。浏览上下文文档的概念是这样解释的浏览上下文是浏览器显示文档(现在通常是选项卡,但也可能是页面中的窗口或框架)的环境。每个浏览上下文都有一个特定的来源、主机(域)和用于访问它的URL的端口。只有当方案、主机和端口都匹配时,两个对象才具有相同的来源。”),活动文档的来源,以及按顺序列出所有显示文档的历史记录。简单理解,一个tab页,一个frame就是一个浏览上下文文档的来源本文档还解释了Web内容的来源是由scheme(协议)、host(域)、访问它的URL的端口定义的。只有方案、主机和端口都匹配时,两个对象才具有相同的来源。简单理解,这就是我们常说的域。明白了这两个概念,再看这个文档,跟我们测试的结论是一样的。更简单的总结就是:在页面a中会存在一个通过window.open()打开的同域页面的页面当前sessionStorage的单独副本。这就是看起来像sessionStorage继承问题的解释。当然,这里的继承并不是真正的继承,只是看起来像这样。在查资料的过程中,发现有兄弟想避免这种继承。当然这个回避方法也有提到(个人感觉不是很优雅),就是加载完后重启新打开的b页面。设置sessionStorage,以免被上一页影响。参考文档API/Using_the_Web_Storage_APIAPI/Window/sessionStorageproject-sessionStoragehow-to-prevent-sessionstorage-being-inherited-when-using-target-blank-windowthe-sessionstorage-attributeoriginBrowsing_context