localStorage的寫入和讀取,不能跨子域,否則在一些移動端瀏覽器上,會出現讀取不到的情況。
最近開發一個移動端的播放記錄功能,在pc端和android版的chrome測試很順利通過了,但后來進行多平台測試的時候,悲劇發生了。。
掉進localStorage的坑里
android版本UC、iphone及ipad mini版的safari,localStorage跨頁面讀取不到數據,必須要重啟瀏覽器后才能夠正常的讀取到數據。
爬出localStorage的坑
首先懷疑的可能是localStorage的訪問方式的問題,寫入的方式是屬性設置localStorage.history而讀取是api的方式localStorage.getItem,demo后確認localStorage的三種訪問方式都是沒有問題的。
思維短路了,開始思考如何規避這個跨頁面無法讀取的問題,首先想到的是嘗試下sessionStorage,瀏覽器運行期間將數據保存在“session”中,后來發現有着同樣的問題。
繼續思考能夠跨頁面保存“大數據”的方式,“靈光”閃現,window.name應該是可以跨頁面保存的,試了下各種設備確認這種方案確實可行,但是風險是任何頁面都有可能重寫掉這個name,甚至會有安全問題。
用極簡的demo測試,發現這些有問題的瀏覽器對localStorage的支持是沒問題的。在幾乎要放棄的時候,同事跑過來說,將某個文件提前到head里,可以正常的讀取數據,這是才意識到播放器的前置代碼里沒有顯示的設置document.domain,導致讀取和設置localStorage在不同的domain下面發生的。
在寫入localStorage的頁面方法之前沒有顯示的設置document.domain,默認的值為 labs.wxnet.me,但是在讀取的頁面,讀取數據之前顯示的設置了document.domain為根域wxnet.me
將問題環境抽象為demo
寫入數據的頁面 http://labs.wxnet.me/labs/writelocalstorage.html
//document.domain默認值為子域 labs.wxnet.me localStorage['k'] = '{"a":"1"}'; document.domain = "wxnet.me";
讀取數據的頁面 http://labs.wxnet.me/labs/readlocalstorage.html
document.domain = "wxnet.me"; alert(localStorage['k']);
解決方案
讀取和設置localStorage的頁面必須要統一document.domain,要么全部不顯示設置或統一設置為根域。
設置頁面:
document.domain = "wxnet.me"; localStorage['k'] = '{"a":"1"}';
讀取頁面:
document.domain = "wxnet.me"; alert(localStorage['k']);
思考
不同的移動版瀏覽器在處理子域方式不同,iphone、ipad mini子域下寫入,主域下是無法讀取的,重啟瀏覽器后忽略掉這個安全策略,可以讀到數據。但是ipad、pc版的瀏覽器沒有發現這個問題。