blog
blog copied to clipboard
sessionStorage 的数据会在同一网站的多个标签页之间共享吗?这取决于标签页如何打开
一直以来,我所以为的 sessionStorage 的生命周期是这样的:在 sessionStorage 中存储的数据会在当前浏览器的同一网站的多个标签页中共享,并在此网站的最后一个标签页被关闭后清除。注意:这是错误的。
我之所以会这么认为,是因为我写代码的时候,sessionStorage 给我的表现就是这样的。
假设我们有一个 index.html:
<!-- 使用一个新标签页打开自身,并设置一个 sessionStorage -->
<a href="index.html" target="_blank" onclick="sessionStorage.setItem('j', 's')">
open myself
</a>
接下来:
- 在浏览器中打开这个 index.html,我们称之为标签页 A。注意:需要用 http 协议打开!例如 http://localhost/index.html
- 点击页面上的链接,此时会弹出来标签页 B。
- 在标签页 B 中打开控制台并执行
sessionStorage.getItem('j')
控制台会输出 's',这说明标签页 A 和 B 共享了 sessionStorage 中的数据;接下来,先关闭这两个标签页,然后再打开一个标签页 C,再读取一下 j 的值,得到的是 null。
这看起来跟本文一开始的说法是一致的,但今天我遇到了一个奇怪的事情……
我们给上面的步骤添加第四步:
- 在浏览器中打开这个 index.html,我们称之为标签页 A。注意:需要用 http 协议打开!例如 http://localhost/index.html
- 点击页面上的链接,此时会弹出来标签页 B。
- 在标签页 B 中打开控制台并执行
sessionStorage.getItem('j'),得到's' - 新建一个新标签页 D,然后在地址栏内输入 http://localhost/index.html 打开同样的页面, 然后执行
sessionStorage.getItem('j')。
按照我的预期,标签页 D 得到的应该还是 's',毕竟我认为 sessionStorage 的数据是在同一网站的多个标签页之间共享的。但是我错了,得到的结果是 null。
发生了什么?为什么标签页 B 中得到的是 's',为什么标签页 D 中却是 null?
细心的同学可能已经发现了,标签页 B 和标签页 D 之间唯一的不同就是它们被打开的方式:标签页 B 是通过在标签页 A 中点击链接打开的,但标签页 D 是在浏览器地址栏输入地址打开的。
我赶紧上 MDN 查了一下,上面是这么说的:
...data stored in sessionStorage gets cleared when the page session ends...Opening a page in a new tab or window will cause a new session to be initiated, which differs from how session cookies work.
所以现在我明白了:通过点击链接(或者用了 window.open)打开的新标签页之间是属于同一个 session 的,但新开一个标签页总是会初始化一个新的 session,即使网站是一样的,它们也不属于同一个 session。
一点题外话
这个问题是我今天在 Stack Overflow 上回答一个问题的时候发现的,在答案的例子中我使用 sessionStorage 保存了一个状态,然后测试的时候发现新开的标签页居然读不到。
这也从侧面验证了一个道理:在帮助别人的时候,自己也会从中得到提升。
所以我决定以后多多帮助别人 😂
P.S. 之所以今天会跑到 Stack Overflow 上回答问题是因为我必须有一个答案被采纳之后才够等级给别人的答案投票 😂
题主,对于新开一个tab,然后输入网址的方式,要想共享sessionStorage应该怎么做?
@myst729 还能转卖?
哈哈,我也遇到了这个问题。
很有帮助,感谢
题主,对于新开一个tab,然后输入网址的方式,要想共享sessionStorage应该怎么做?
用localstorage咯?
题主,对于新开一个tab,然后输入网址的方式,要想共享sessionStorage应该怎么做?
class MemoryStorage { constructor(handler) { this.storage = {} this.handler = handler }
isEmpty() {
const o = this.storage
for (var i in o) {
return false
}
return true
}
addSessionToStorage() {
for (let i = 0; i < sessionStorage.length; i++) {
const key = sessionStorage.key(i)
this.storage[key] = sessionStorage.getItem(key)
}
}
addStorageToSession() {
let data = localStorage.getItem('sessionStorage')
data = JSON.parse(data)
for (let i in data) {
sessionStorage.setItem(i, data[i])
}
}
addEvent() {
window.addEventListener('storage', event => {
if (event.key === 'getSessionStorage') {
this.addSessionToStorage()
localStorage.setItem('sessionStorage', JSON.stringify(this.storage))
} else if (event.key == 'sessionStorage' && this.isEmpty()) {
this.addStorageToSession()
localStorage.removeItem('sessionStorage')
}
})
}
}
const memory = new MemoryStorage()
export const Memory = function() { memory.addEvent()
if (memory.isEmpty()) {
localStorage.setItem('getSessionStorage', Date.now());
}
}
export const memoryInstance = memory
上面的代码就是共享状态的 今天刚折腾出来的 核心就是window.addEventListener
当你把B页面的seesionStorage的值改变了,你会发现A页面的sessionStorage的值没有改变
当你把B页面的seesionStorage的值改变了,你会发现A页面的sessionStorage的值没有改变
这个确实也是很蛋疼,新开窗口实际上只是继承了,并不是共享
you are wrong! when you open a new tab by target, session will also be cleared !
简单总结:
localStorage- 只要是同源,不同 Tab 之间均可读写,相互影响。sessionStorage- 前提还是同源,- 同一 Tab 的所有同源可读写且相互影响。
- 不同 Tab 之间,读写操作独立,“互不影响”。
- 上面打引号原因是,
<a target="_blank"></a>和window.open()两种方式创建新 Tab 的初始缓存不一样。前者是全新的一个sessionStorage对象,且初始值为空。后者则基于原页面的sessionStorage拷贝一份,并作为新 Tab 的初始缓存值。
Cookie- 只要Domain和Path一致情况下,不同 Tab 之间即可相互读取。Cookie最宽松的情况是同站即可,就是说Domain设为二级域名、Path设为/。
PS:同源和同站是有区别的,同源更严格一些。
cookie还可以设置path
cookie还可以设置path
对对对,Cookie 受 Domain 和 Path 限制。我这里只是为了突出同源和同站,所以假定 Domain 为二级域名,Path 为 /。
我去修改下