之前对sessionStorage的了解很表面,粗略的理解为在各标签页/窗口下独立,生命周期和标签页/窗口关联,标签页/窗口未关闭就存在(除人为清除或者调用相关api删除)。但是这种粗略的理解对于下面的场景似乎就有点不明确了。
- 如果一个文档通过iframe嵌入了一个同源的地址,那这个文档和嵌入的iframe的sessionStorage是否共享?【是】
- 如果一个文档通过iframe嵌入一个同源地址两次,那么这两个同源地址的sessionStorage是否共享?【是】
- 如果想让iframe嵌入的地址共享当前文档的sessionStorage是否可以实现?
- 不同标签页之间能实现sessionStorage共享吗【不能。但是可以在创建标签页的时候用当前页的sessionStorage初始化新标签】
1. MDN中对sessionStorage的解释:
sessionStorage 属性允许你访问一个,对应当前源的 session Storage 对象。它与 localStorage 相似,不同之处在于 localStorage 里面存储的数据没有过期时间设置,而存储在 sessionStorage 里面的数据在页面会话结束时会被清除。
- 页面会话在浏览器打开期间一直保持,并且重新加载或恢复页面仍会保持原来的页面会话。
- 在新标签或窗口打开一个页面时会复制顶级浏览会话的上下文作为新会话的上下文,这点和 session cookie 的运行方式不同。
- 打开多个相同的 URL 的 Tabs 页面,会创建各自的 sessionStorage。
- 关闭对应浏览器标签或窗口,会清除对应的 sessionStorage。
除了第2点,其他几个特性和我们日常理解的大差不差,我将结合下面W3中的解释总结。
2.W3中的解释:
下面我们逐句理解:
2.1 sessionStorage特性代表了当前顶级浏览上下文指定的存储区域。每个顶层浏览上下文都有唯一的一套会话存储区域,其中每个源有一个会话存储区域
1. 顶级上下文:
平时我们说的浏览上下文可以是一个标签页、一个窗口、一个iframe等。而顶级浏览上下文就是没有被嵌入到任何其他浏览上下文的浏览上下文,一般情况下,在浏览器中打开一个新的标签页或者窗口时,这个新的标签页或窗口就是一个顶级浏览上下文,而一个iframe被嵌入另一个文档中时,那这个iframe浏览上下文就不是顶级浏览上下文。平时开发中我们可能会通过比较window.top与window.self是否相等来判断当前浏览上下文是否时顶级上下文
2. 每个顶层浏览上下文都有唯一的一套会话存储区域,其中每个源有一个会话存储区域:
由于一个顶级上下文中可能包含多个浏览上下文,所以它有一套会话存储区域,而每个源(同域)有一个会话存储区域。
那么是不是就可以理解为,如果在一个顶级浏览上下文中如果嵌套了两个同源的浏览上下文(如通过iframe),这两个浏览上下文是不是共享一个sessionStorage会话存储区域?
答案是肯定的
同样如果顶级浏览上下文和其嵌套的浏览上下文同源的话,其sessionStorage也是共享的。
注意这里提到的是共享,不是复制,他们不是相互独立的,而是使用的同一个存储区域。
这就可以回答文章开头的问题1和问题2,答案都是肯定的。
2.2
当一个新的Document在一个顶级浏览上下文中被创建时,用户代理必须检查该顶级浏览上下文在当前文档的源下,是否具有会话存储区域。如果有,那么这个存储区域就是这个Document分配的会话存储区域;如果没有,则会为该文档的源创建一个新的存储区域,并作为该Document分配的会话存储区域。一个Document分配的会话存储区域在其生命周期内是不会改变的——甚至在一个嵌套的浏览上下文(比如iframe)被移动到另一个父浏览上下文的时候。
结合2.1的内容,这句话就更容易理解了。当一个新的Document被创建时会先查找当前顶级浏览上下文中是否已经有同源的存储区域,如果已经有了就直接使用该区域,如果没有则新建一个存储区域。
最后回答下上面提到的问题3和4:
1.sessionStorage完全不能在两个窗口共享吗?
一般来说,在不同窗口sessionStorage是隔离的,互不影响。但是通过window.open(url,‘_blank’)在新窗口打开同域下的地址,新开的窗口会复制当前窗口的sessionStorage为新窗口的sessionStorage,但是后续两个窗口的sessionStorage互不影响。即新窗口使用了原来窗口的sessionStorage做初始化,使用方式如:
2.系统A通过iframe嵌入系统B时,系统B能否共享A的sessionStorage?
- 如果A和B是在同一个域名下
B和A共享sessionStorage - 如果A和B不同域
则两者的sessionStorage独立,此时如果想想A共享B的sessionStorage,可以通过nginx代理的方式,来实现两者在一个域名下的效果。如:B在嵌入A是不使用绝对地址,而是使用一个自定义的前缀路径,nginx在根据这个前缀代理到实际的地址,举例:
location /database/ {
proxy_pass http://192.168.12.188:32510/;
}