Safari Private 模式下 localStorage 的問題

劉哇勇發表於2017-06-17

現如今好多瀏覽器都有「隱身模式」,Safari 管這叫「Private Browing」,國內各種牌子的套殼瀏覽器叫「無痕瀏覽」。私以為從命名上來說,倒是國內更中文一些。

這種模式下瀏覽網頁踏雪無痕,雁過不留聲。具體來說,與正常模式的區別是瀏覽器不會儲存歷史記錄,沒有頁面快取,所有本地資料也都是臨時的,頁面關閉後無法還原。譬如本文下面要講到的 localStorage

並不是說這種模式下絕對安全,伺服器仍然對使用者的瀏覽是有感知的。所以 IP 什麼的依然可以追蹤。
這世界並不如我們天真設想般爛漫。

--------- LOG ---------
00:01:00 - 一位不具名使用者在零點零一分進行了訪問
00:02:00 - 一位不願透露姓名的使用者在零點零二分開啟了你丟棄在伺服器 `社會科學/東方藝術鑑賞/東瀛浮世繪` 中的資源 `ae2bx86.jpg`

從功能上來說,普通使用者大概鮮有人知道這一功能(產品情懷就這樣被使用者無視,PM 們默默淚目),而開發者則利用其乾淨的特點來開發除錯,排除程式之外的因素導致 bug 的可能。

因為所有本地資料都是臨時的,那麼問題來了,如果網頁程式碼中還使用了諸如 localStorage 的本地儲存,還能生效嗎?

答案是肯定的,但只針對本次訪問。這個肯定只限於桌面瀏覽器。 而手機端則不然。

iOS 上 Safari private 模式下瀏覽器假裝支援 localStorage,並在全域性 window 上暴露了該方法。但是當你在呼叫 localStorage.setItem 進行儲存的時候就會報 QUOTA_EXCEEDED_ERR 錯。

QUOTA_EXCEEDED_ERR:DOM Exception 22:An attempt was made to add something to storage...

考察下面的測試程式碼:

<button class="setValue">SET</button>
<hr>
<button class="getValue">GET</button>
<script>
    var q = document.querySelector;
    document.querySelector('.setValue').onclick = function () {
        try {
            var time = new Date().getTime();
            localStorage.setItem('time', time);
            alert('set '+time);
        } catch (error) {
            alert(JSON.stringify(error));
        }
    }
    document.querySelector('.getValue').onclick = function () {
        var content = localStorage.getItem('time', new Date().getTime());
        alert('got '+content);
    }
</script>

我在頁面放了兩個按鈕,一個用於向瀏覽器儲存值,一個用於獲取。

下面是測試結果:

iOS Safari 隱私模式設定值
iOS Safari 隱私模式設定值

iOS Safari 隱私模式獲取值
iOS Safari 隱私模式獲取值

iOS Chrome 隱私模式設定值
iOS Chrome 隱私模式設定值

iOS Chrome 隱私模式獲取值
iOS Chrome 隱私模式設取值

這表明在 iOS 上,不僅是 Safari 在隱私模式中不能使用 localStorage, Chrome 也不行也不行。這不禁讓人懷疑跟系統平臺的策略有關。

博主是穀粉,很早就入手了 Nexus。本著嚴謹的做事態度,那肯定也得拿來測試一下丫。而安卓機上的測試則讓人無法接受。

安卓 Chrome 隱私模式下設定值
安卓 Chrome 隱私模式下設定值

安卓 Chrome 隱私模式下獲取值
安卓 Chrome 隱私模式下獲取值

是的,安卓上面並沒有表現出假裝支援 localStorage,而是真正的支援,能存能取,能取能用!再次證實了上面的懷疑,這種假裝的支援應該是 iOS 的設計哲學。

回過頭來想,隱私模式主要的功能不就是讓使用者的資料不被追蹤嗎,如果能夠存取資料的話,反而沒那麼隱私了。從這點來說,localStorage 設定不成功倒也考量了些許人文情懷在裡面。

問題想當於回到了開發者手中,我們在開發過程中使用 loaclStorage 就需要對這種情況進行相容,以避免 js 報錯後影響整個頁面的功能。

下面是相容程式碼示例:

function isLocalStorageSupport(){
    try {
        var isSupport = 'localStorage' in window && window['localStorage'] !== null;
        if (isSupport) {
            localStorage.setItem('__test', '1');
            localStorage.removeItem('__test');
        }
        return isSupport;
    } catch (e) {
        return false;
    }
}

為此,我們可以考慮提取一個輔助類來封裝 localStorage,這樣就可以隨時隨地放心使用。

相關文章