Safari無痕模式下,storage被禁用問題
前言
Safari開啟無痕模式後,localStorage和sessionStorage為空,對其進行set操作也會報錯,也就是說這種情況下,storage是被禁止使用了。接下來說一下解決方法。
解決方案
我們專案框架上的解決方法是對storage進行一層封裝,遇到這種開啟無痕模式的情況,會定義一個window的全域性變數,把之前準備存放到storage的內容改為存到這個全域性變數中。
注意,無痕模式下localStorage和sessionStorage物件本身依然是存在的,只是呼叫setItem方法是會報錯。下面是無痕模式下報錯的截圖:
所以正確的判斷程式碼應該是這樣:
try { sessionStorage.setItem('private_test', 1); } catch (e) { //無痕模式 }
我們會另外定義一個NameStorage物件,在原生storage失效時使用:
// 隱私模式下面,把臨時值存到window.name中去 function NameStorage(type) { this.store = NameStorage[type]; } Object.assign(NameStorage.prototype, { getItem: function(key) { return this.store[key]; }, setItem: function(key, value) { this.store[key] = value; this._saveNameValue(); }, removeItem: function(key) { delete this.store[key]; this._saveNameValue(); }, clear: function() { this.store = {}; this._saveNameValue(); }, _saveNameValue: function() { var ret = { session: NameStorage.session, local: NameStorage.local } window.name = JSON.stringify(ret); } });
上面會把所有的local和session資料儲存到window.name上去,然後在每個頁面啟動時,呼叫一下keepName方法,把window.name的資料拿下來放到NameStorage上面。這時候,只需要呼叫new NameStorage('local')來代替localStorage進行操作就行了
function keepName () { if (keepName.done) { return; } var ret; if (window.name) { try { ret = JSON.parse(window.name); } catch (e) { ret = {}; } } if (!_.isPlainObject(ret)) { ret = {}; } if (!ret.session) { ret.session = {}; } if (!ret.local) { ret.local = {}; } NameStorage.session = ret.session; NameStorage.local = ret.local; keepName.done = true; }
另外一些補充
● 無痕模式下,localStorage和sessionStorage的報錯資訊是:QuotaExceededError,code為22,這個其實是storage儲存空間用完了報的錯,就比如當前瀏覽器storage記憶體為5mb,你已經儲存了5mb的資料後,再進行setItem操作就會報這個錯誤。
● 所以我猜想無痕模式下,瀏覽器是把storage的記憶體先清空,然後再設定最大值為0,這樣呼叫setItem就直接報錯了。
● 另外無痕模式下cookie是可以使用的,大概因為cookie是跟伺服器有關,而storage是屬於瀏覽器的特性吧。
● 最後還有一種情況,就是無痕模式下打開了某個頁面,然後把瀏覽器關閉再開啟,這個時候會開啟訪問的頁面,但是window.name已經丟失了,所以就拿不到以前儲存的資料了。這種情況只能頁面做容錯處理了。