Cześć, pomagam w utrzymaniu safaridriver. Ten problem to występujący od dawna błąd w oprogramowaniu WebKit, który został niedawno naprawiony. Lokalna pamięć masowa i pamięć sesji działają teraz w przeglądarce Safari 10.1 i nowszych. Ta poprawka dotyczy normalnego trybu przeglądania prywatnego i trybu automatyzacji (używanego przez WebDriver).
Najwyraźniej jest to zamierzone. Gdy Safari (OS X lub iOS) jest w trybie przeglądania prywatnego, wygląda na localStorageto, że jest dostępne, ale próba wywołania setItemzgłasza wyjątek.
store.js line 73"QUOTA_EXCEEDED_ERR: DOM Exception 22: An attempt was made to add something to storage that exceeded the quota."
Dzieje się tak, że obiekt okna nadal uwidacznia się localStoragew globalnej przestrzeni nazw, ale podczas wywołania setItemzgłaszany jest ten wyjątek. Wszelkie wezwania do removeItemsą ignorowane.
Uważam, że najprostszą poprawką (chociaż nie testowałem jeszcze tej przeglądarki) byłaby zmiana funkcji, isLocalStorageNameSupported()aby sprawdzić, czy można również ustawić jakąś wartość.
Podobnie jak w przypadku Paula Irisha, proponuję zmienić return localStorageName in win && win[localStorageName];na return true. Następnie masz funkcję, która bezpiecznie zwraca wartość true lub false w zależności od dostępności localStorage. Na przykład:if (isLocalStorageNameSupported()) { /* You can use localStorage.setItem */ } else { /* you can't use localStorage.setItem */ }
Czy jest jakiś szczególny powód, dla którego (i @KingKongFrog) używasz window.sessionStorage do wykrywania, czy możesz pisać do localStorage, czy też jesteśmy w dziwnym cyklu literówek kopiuj-wklej?
@Yetti Jeśli zauważyłeś literówkę, dlaczego nie poprawisz jej w edycji lub w komentarzu? O ile mi wiadomo, window.sessionStorageto prawda. Z pewnością działa w moim kodzie. Wskaż sposób rozwiązania problemu, o którym wiesz.
@Novocaine Mój komentarz wskazywał, że używają sessionStorage w funkcji, która istnieje do sprawdzania obsługi localStorage. Tak, prawdopodobnie nadal będzie działać, ale jak napisano, nazwa funkcji wprowadza w błąd co do tego, co jest faktycznie testowane. Wolałem komentować niż edytować, ponieważ myślałem, że czegoś mi brakuje i miałem nadzieję, że nauczę się od tych gości. Niestety, nie odpowiedzieli ani nie wprowadzili korekty, więc oto jesteśmy.
@DawsonToth nie, ponieważ wywołałem funkcję isLocalStorageNameSupportedi sprawdzałem window.sessionStorage. Ten sam efekt końcowy, ale był trochę zagmatwany. Odpowiedź została zredagowana w celu wyjaśnienia.
Jak wspomniano w innych odpowiedziach, zawsze otrzymasz błąd QuotaExceededError w trybie przeglądarki prywatnej Safari w systemie iOS i OS X, gdy zostanie wywołany localStorage.setItem(lub sessionStorage.setItem).
Jednym z rozwiązań jest wykonanie testu try / catch lub Modernizr w każdym przypadku użycia setItem.
Jeśli jednak potrzebujesz podkładki, która po prostu globalnie zapobiega zgłaszaniu tego błędu, aby zapobiec uszkodzeniu reszty JavaScript, możesz użyć tego:
// Safari, in Private Browsing Mode, looks like it supports localStorage but all calls to setItem// throw QuotaExceededError. We're going to detect this and just silently drop any calls to setItem// to avoid the entire page breaking, without having to do a check at each usage of Storage.if(typeof localStorage ==='object'){try{
localStorage.setItem('localStorage',1);
localStorage.removeItem('localStorage');}catch(e){Storage.prototype._setItem =Storage.prototype.setItem;Storage.prototype.setItem =function(){};
alert('Your web browser does not support storing settings locally. In Safari, the most common cause of this is using "Private Browsing Mode". Some settings may not save or some features may not work properly for you.');}}
W moim kontekście właśnie opracowałem abstrakcję klas. Po uruchomieniu aplikacji sprawdzam, czy działa localStorage, wywołując metodę getStorage () . Ta funkcja zwraca również:
albo localStorage, jeśli działa localStorage
lub implementację niestandardowej klasy LocalStorageAlternative
W moim kodzie nigdy nie dzwonię bezpośrednio do localStorage. Wzywam cusSto globalny var miałem zainicjowane przez wywołanie getStorage () .
W ten sposób działa z przeglądaniem prywatnym lub określonymi wersjami Safari
Dzięki, Pierre, twoja odpowiedź mnie zainspirowała. Skończyło się na tym, że zapakowałem to wszystko w ładny moduł zwany memorystorage . Oczywiście Open Source. W przypadku innych osób z tym samym problemem sprawdź, czy może ci to pomóc.
Ha. Zrobiłem to samo (niezależnie). Nadal jednak używaj zmiennej localStorage (przynajmniej w Safari nie możesz nadpisać zmiennej localStorage (jest to „tylko do odczytu”), ale możesz ponownie przypisać setItem / removeItem / getItem).
@StijndeWitt, jak mogę uzyskać dostęp do moich wartości przechowywania na innych stronach? Na przykład mam to w moim helper.php var store = MemoryStorage ('my-app'); store.setItem ('myString', 'Hello MemoryStorage!'); Chcę uzyskać dostęp do wartości myString w lecture.php. Próbowałem zainicjować przechowywanie pamięci na stronie, ale nadal pokazuje ona pusty obiekt.
Adres @ user1149244 Memorystorage jest lokalny dla strony. Symuluje interfejs API usługi Web Storage i jako taki może służyć jako rezerwa, gdy localStorage i sessionStorage nie są dostępne. Jednak dane zostaną zachowane tylko w pamięci strony (stąd nazwa). Jeśli chcesz, aby dane były przechowywane na różnych stronach, mogą Ci pomóc pliki cookie. Ale ilość danych, które można przechowywać, jest bardzo ograniczona. Poza tym niewiele można zrobić.
@ user1149244 Czy to rzekomo nie przechowuje wartości w przeglądarce? Nie, nie może. Istnieją 3 sposoby przechowywania informacji po stronie klienta z jednej strony odświeżanej na drugą: pliki cookie, sessionStorage / localStorage i IndexedDB. Ostatnie dwa są stosunkowo nowe. sessionStorage i localStorage są szeroko obsługiwane, więc możesz ich używać praktycznie wszędzie. z wyjątkiem trybu przeglądania prywatnego , o co chodzi w tym problemie. Programy się zepsuły, ponieważ nie było tam pamięci. memorystorage zapewnia po prostu rezerwę, która zawsze działa na stronie, ale nie może w rzeczywistości zapisać danych. To jest kikut. Ale bez błędu.
Wygląda na to, że Safari 11 zmienia zachowanie, a teraz pamięć lokalna działa w prywatnym oknie przeglądarki. Brawo!
Nasza aplikacja internetowa, która wcześniej nie działała podczas przeglądania prywatnego w Safari, teraz działa bez zarzutu. Zawsze działało dobrze w trybie przeglądania prywatnego Chrome, który zawsze pozwalał na zapisywanie w pamięci lokalnej.
Aby rozwinąć odpowiedzi innych osób, oto kompaktowe rozwiązanie, które nie ujawnia / nie dodaje żadnych nowych zmiennych. Nie obejmuje wszystkich baz, ale powinien odpowiadać większości osób, które chcą, aby aplikacja z jedną stroną pozostała funkcjonalna (pomimo braku trwałości danych po ponownym załadowaniu).
Miałem ten sam problem używając frameworka Ionic (Angular + Cordova). Wiem, że to nie rozwiązuje problemu, ale jest to kod dla Angular Apps oparty na powyższych odpowiedziach. Będziesz mieć efemeryczne rozwiązanie dla localStorage w wersji Safari na iOS.
Chociaż to nie odpowiada na pytanie, jest to pierwsza rzecz, która pojawiła się, gdy wyszukałem ten problem w Google. Następnym krokiem byłoby poszukiwanie rozwiązania dla Angulara, ale dzięki temu komentarzowi nie muszę nigdzie indziej iść. Więc może nie odpowiadać bezpośrednio na pytanie, ale był świetny dla mnie i prawdopodobnie dla innych!
Powoduje to, isLocalStorageAvailableże jest ustawiana natychmiast po pierwszym wstrzyknięciu usługi i pozwala uniknąć niepotrzebnego przeprowadzania sprawdzania za każdym razem, gdy trzeba uzyskać dostęp do pamięci lokalnej.
angular.module('app.auth.services',[]).service('Session',['$log','$window',functionSession($log, $window){var isLocalStorageAvailable =(function(){try{
$window.localStorage.world ='hello';delete $window.localStorage.world;returntrue;}catch(ex){returnfalse;}})();this.store =function(key, value){if(isLocalStorageAvailable){
$window.localStorage[key]= value;}else{
$log.warn('Local Storage is not available');}};}]);
Zestawy StorageService.localStoragedo window.localStoragejeśli jest obsługiwany lub tworzy przechowywania cookie. Zestawy StorageService.sessionStoragedo window.sessionStoragejeśli jest obsługiwany lub tworzy w pamięci do przechowywania, magazynowania SPA ciasteczka z funkcji Sesión za nieprzestrzeganie SPA.
Oto wersja usługi Angular2 + dla alternatywnego przechowywania pamięci, którą możesz po prostu wstrzyknąć do swoich komponentów, w oparciu o odpowiedź Pierre'a Le Roux.
import{Injectable}from'@angular/core';// Alternative to localstorage, memory// storage for certain browsers in private modeexportclassLocalStorageAlternative{private structureLocalStorage ={};
setItem(key: string, value: string):void{this.structureLocalStorage[key]= value;}
getItem(key: string): string {if(typeofthis.structureLocalStorage[key]!=='undefined'){returnthis.structureLocalStorage[key];}returnnull;}
removeItem(key: string):void{this.structureLocalStorage[key]=undefined;}}@Injectable()exportclassStorageService{private storageEngine;constructor(){try{
localStorage.setItem('storage_test','');
localStorage.removeItem('storage_test');this.storageEngine = localStorage;}catch(err){this.storageEngine =newLocalStorageAlternative();}}
setItem(key: string, value: string):void{this.storageEngine.setItem(key, value);}
getItem(key: string): string {returnthis.storageEngine.getItem(key);}
removeItem(key: string):void{this.storageEngine.removeItem(key);}}
Stworzyłem łatkę na ten problem. Po prostu sprawdzam, czy przeglądarka obsługuje localStorage lub sessionStorage, czy nie. Jeśli nie, to mechanizm przechowywania będzie Cookie. Ale negatywną stroną jest to, że Cookie ma bardzo małą pamięć :(
functionStorageEngine(engine){this.engine = engine ||'localStorage';if(!this.checkStorageApi(this.engine)){// Default engine would be alway cooke// Safari private browsing issue with localStorage / sessionStoragethis.engine ='cookie';}}StorageEngine.prototype.checkStorageApi =function(name){if(!window[name])returnfalse;try{var tempKey ='__temp_'+Date.now();
window[name].setItem(tempKey,'hi')
window[name].removeItem(tempKey);returntrue;}catch(e){returnfalse;}}StorageEngine.prototype.getItem =function(key){if(['sessionStorage','localStorage'].includes(this.engine)){return window[this.engine].getItem(key);}elseif('cookie'){var name = key+"=";var allCookie = decodeURIComponent(document.cookie).split(';');var cval =[];for(var i=0; i < allCookie.length; i++){if(allCookie[i].trim().indexOf(name)==0){
cval = allCookie[i].trim().split("=");}}return(cval.length >0)? cval[1]:null;}returnnull;}StorageEngine.prototype.setItem =function(key, val, exdays){if(['sessionStorage','localStorage'].includes(this.engine)){
window[this.engine].setItem(key, val);}elseif('cookie'){var d =newDate();var exdays = exdays ||1;
d.setTime(d.getTime()+(exdays*24*36E5));var expires ="expires="+ d.toUTCString();
document.cookie = key +"="+ val +";"+ expires +";path=/";}returntrue;}// ------------------------varStorageEngine=newStorageEngine();// new StorageEngine('localStorage');// If your current browser (IOS safary or any) does not support localStorage/sessionStorage, then the default engine will be "cookie"StorageEngine.setItem('keyName','val')var expireDay =1;// for cookie onlyStorageEngine.setItem('keyName','val', expireDay)StorageEngine.getItem('keyName')
Przyjęta odpowiedź wydaje się nieadekwatna w kilku sytuacjach.
Aby sprawdzić, czy obsługiwane localStoragelub sessionStoragesą obsługiwane, używam następującego fragmentu z MDN .
function storageAvailable(type){var storage;try{
storage = window[type];var x ='__storage_test__';
storage.setItem(x, x);
storage.removeItem(x);returntrue;}catch(e){return e instanceofDOMException&&(// everything except Firefox
e.code ===22||// Firefox
e.code ===1014||// test name field too, because code might not be present// everything except Firefox
e.name ==='QuotaExceededError'||// Firefox
e.name ==='NS_ERROR_DOM_QUOTA_REACHED')&&// acknowledge QuotaExceededError only if there's something already stored(storage && storage.length !==0);}}
Użyj tego fragmentu kodu w ten sposób i wróć do, na przykład, pliku cookie:
if(storageAvailable('localStorage')){// Yippee! We can use localStorage awesomeness}else{// Too bad, no localStorage for us
document.cookie = key +"="+ encodeURIComponent(value)+ expires +"; path=/";}
Zrobiłem pakiet fallbackstorage , który używa tego fragmentu kodu do sprawdzenia dostępności magazynu i powrotu do ręcznie zaimplementowanego MemoryStorage.
import{getSafeStorage}from'fallbackstorage'
getSafeStorage().setItem('test','1')// always work
// Fake localStorage implementation. // Mimics localStorage, including events. // It will work just like localStorage, except for the persistant storage part. var fakeLocalStorage =function(){var fakeLocalStorage ={};var storage;// If Storage exists we modify it to write to our fakeLocalStorage object instead. // If Storage does not exist we create an empty object. if(window.Storage&& window.localStorage){
storage = window.Storage.prototype;}else{// We don't bother implementing a fake Storage object
window.localStorage ={};
storage = window.localStorage;}// For older IEif(!window.location.origin){
window.location.origin = window.location.protocol +"//"+ window.location.hostname +(window.location.port ?':'+ window.location.port:'');}var dispatchStorageEvent =function(key, newValue){var oldValue =(key ==null)?null: storage.getItem(key);// `==` to match both null and undefinedvar url = location.href.substr(location.origin.length);var storageEvent = document.createEvent('StorageEvent');// For IE, http://stackoverflow.com/a/25514935/1214183
storageEvent.initStorageEvent('storage',false,false, key, oldValue, newValue, url,null);
window.dispatchEvent(storageEvent);};
storage.key =function(i){var key =Object.keys(fakeLocalStorage)[i];returntypeof key ==='string'? key :null;};
storage.getItem =function(key){returntypeof fakeLocalStorage[key]==='string'? fakeLocalStorage[key]:null;};
storage.setItem =function(key, value){
dispatchStorageEvent(key, value);
fakeLocalStorage[key]=String(value);};
storage.removeItem =function(key){
dispatchStorageEvent(key,null);delete fakeLocalStorage[key];};
storage.clear =function(){
dispatchStorageEvent(null,null);
fakeLocalStorage ={};};};// Example of how to use itif(typeof window.localStorage ==='object'){// Safari will throw a fit if we try to use localStorage.setItem in private browsing mode. try{
localStorage.setItem('localStorageTest',1);
localStorage.removeItem('localStorageTest');}catch(e){
fakeLocalStorage();}}else{// Use fake localStorage for any browser that does not support it.
fakeLocalStorage();}
Sprawdza, czy localStorage istnieje i może być używany, aw negatywnym przypadku tworzy fałszywą lokalną pamięć masową i używa jej zamiast oryginalnego localStorage. Daj mi znać, jeśli potrzebujesz dodatkowych informacji.
Używamy plików cookie i innych technologii śledzenia w celu poprawy komfortu przeglądania naszej witryny, aby wyświetlać spersonalizowane treści i ukierunkowane reklamy, analizować ruch w naszej witrynie, i zrozumieć, skąd pochodzą nasi goście.
Kontynuując, wyrażasz zgodę na korzystanie z plików cookie i innych technologii śledzenia oraz potwierdzasz, że masz co najmniej 16 lat lub zgodę rodzica lub opiekuna.