博客 / 詳情

返回

淺談sessionStorage的"繼承"問題

問題復現

最近在寫bug的過程中發現一個有意思的事,我把它稱之為" sessionStorage'繼承' "。我們可以按以下做法復現這一過程:

測試一

打開一個頁面(我們稱之為a頁面),在控制枱執行

sessionStorage.a = 'a';
window.open(window.location.href); // 得到b頁面

我們把新打開的頁面叫做b頁面,然後我們在b頁面控制枱執行

sessionStorage // 直接這麼寫是沒有問題的,相當與獲取window對象的sessionStorage屬性
// 輸出 {a: "a", length: 1}

按照我的認知,一般認為sessionStorage是頁面級的,頁面與頁面之間互不影響。
對於上面這個例子,我期待的輸出應該只有一個length屬性,而不是這種類似'繼承'的表現。
這和我的認知是有差異的,我得查一下。在查文檔之前,我們先對這個問題進行簡單的探索與分析。

初步分析

我按照我的認知測試了一下:

測試二

在a頁面中執行

sessionStorage.a = 'a';

然後複製a頁面的url,新建一個tab頁打開這個url,執行

sessionStorage
// 輸出 {length: 0}

嗯,我的認知也對,只是不全面,缺乏特定場景下的補充。然後我對這個進行了進一步的探索。
在測試一的基礎上我繼續:

測試三

在a頁面控制枱執行

sessionStorage.a = 'aaaaaaaa';
sessionStorage.b = 'b';

在b頁面執行

sessionStorage
// 輸出 {a: "a", length: 1}

至此,綜合測試一二三,我們大概可以得到這樣的信息:
在a頁面通過window.open(window.location.href)得到的b頁面的sessionStorage會有
a頁面當前sessionStorage的一份獨立拷貝,此後再改變a頁面的sessionStorage不會影響到b頁面sessionStorage

這時候我又想,如果在a頁面中打開的不是window.location.href這樣一個地址,而是別的地址,按照我們對localStoragecookie的瞭解,這裏應該也有域的限制。所以我們接着測試:

測試四

我們在a頁面(非https://baidu.com)中打開一個別的域的地址得到c頁面

window.open('https://baidu.com'); // 得到c頁面

我們查看c頁面的sessionStorage發現並沒有a頁面sessionStorage的那些值。恩,這點和我們認知是一樣的,這個"繼承"也只發生在同域的情況下。

所以,總結以上,我們可以得到這樣的信息:
在a頁面通過window.open()打開同域地址得到的b頁面,b頁面會有a頁面當前sessionStorage的一份獨立拷貝,這兩個sessionStorage互不影響。

大概就這麼個結論,那我們去查看看文檔,看看有沒有文檔提到這個結論。

文檔支撐

經過一番搜索我通過這個問題how-to-prevent-sessionstorage-being-inherited-when-using-target-blank-window的答案找到的相應的文檔描述。

When a new Document is created in a browsing context which has a top-level browsing context, the user agent must check to see if that top-level browsing context has a session storage area for that document's origin. If it does, then that is the Document's assigned session storage area. If it does not, a new storage area for that document's origin must be created, and then that is the Document's assigned session storage area. A Document's assigned storage area does not change during the lifetime of a Document.

這是一份html標準文檔(我理解這應該是給瀏覽器廠商看的實現規範),這裏面有兩個概念需要解釋一下

  • browsing context
    這個概念文檔是這麼解釋的

    Abrowsing contextis the environment in which abrowserdisplays aDocument(normally a tab nowadays, but possibly also a window or a frame within a page).

    Each browsing context has a specificorigin, host (domain), and port of the URL used to access it. Two objects have the same origin only when the scheme, host, and port all match."), the origin of the active document, and a history that lists all the displayed documents in order.

    簡單理解,一個tab頁、一個frame就是一個browsing context

  • document's origin
    這個文檔也有解釋

    Web content's origin is defined by the scheme (protocol), host (domain), and port of the URL used to access it. Two objects have the same origin only when the scheme, host, and port all match.

    簡單理解,這就是我們常説的域。

明白了這兩個概念,再看這段文檔,這和我們測試得出來的結論是一樣的,更簡單的總結就是:

在a頁面中通過window.open()打開的同域頁面中會有a頁面當前sessionStorage的一份獨立拷貝。

這就是這個看起來像sessionStorage繼承問題的解釋了。當然了這裏的繼承也並不是真正的繼承,只是看起來像這麼回事。

其他

在查文檔的過程中我發現有些老兄想要避免這種繼承,當然這種避免的方法也是有被人提到的(個人感覺不是很優雅),就是在新打開的b頁面load完之後重置一下sessionStorage,這樣就避免受到上一個頁面的影響了。

參考文檔

  • API/Using\_the\_Web\_Storage\_API
  • API/Window/sessionStorage
  • 項目中踩過的坑之-sessionStorage
  • how-to-prevent-sessionstorage-being-inherited-when-using-target-blank-window
  • the-sessionstorage-attribute
  • origin
  • Browsing_context
user avatar guizimo 頭像 chongdianqishi 頭像 flymon 頭像 uncletong_doge 頭像 susouth 頭像 columsys 頭像 mulander 頭像 tingzhong666 頭像 waweb 頭像 liyl1993 頭像 lesini 頭像 b_a_r_a_n 頭像
26 位用戶收藏了這個故事!

發佈 評論

Some HTML is okay.