QuotaExceededError: Dom-Ausnahme 22: Es wurde versucht, dem Speicher etwas hinzuzufügen, das das Kontingent überschreitet

219

Die Verwendung von LocalStorage auf dem iPhone mit iOS 7 löst diesen Fehler aus. Ich habe mich nach einem Resolvant umgesehen, aber da ich nicht einmal privat surfe, ist nichts relevant.

Ich verstehe nicht, warum localStorage in iOS 7 standardmäßig deaktiviert ist, aber es scheint so? Ich habe auch auf anderen Websites getestet, aber ohne Glück. Ich habe sogar versucht, es über diese Website zu testen: http://arty.name/localstorage.html , aber es scheint aus irgendeinem seltsamen Grund überhaupt nichts zu speichern.

Hat jemand das gleiche Problem gehabt, nur hat er Glück gehabt, es zu beheben? Soll ich meine Speichermethode wechseln?

Ich habe versucht, es zu debuggen, indem ich nur ein paar Zeilen mit Informationen gespeichert habe, aber ohne Erfolg. Ich habe die Standardfunktion localStorage.setItem()zum Speichern verwendet.

Nict
quelle
2
Dies bedeutet normalerweise, dass Sie versucht haben, etwas mit einer Größe zu speichern, die den verfügbaren Speicherplatz überschreitet. Welchen Browser verwenden Sie (Safari, Chrome usw.)? Können Sie etwas mehr von dem Code, den Sie verwendet haben, und wenn möglich die Daten, die Sie speichern möchten, freigeben?
3
Dies sollte als Fehler oder Problem auf der Safari-Seite betrachtet werden. Es macht keinen Sinn, dass Sie localStorage nicht im Inkognito-Modus verwenden können ...
Maksim Luzik
Verwenden Sie eine Funktionserkennung, die Tests für dieses spezielle Problem durchführt . Wenn kein Speicher verfügbar ist, sollten Sie localStorage mit memoryStorage kombinieren . Haftungsausschluss: Ich bin der Autor der verlinkten Pakete
Stijn de Witt
1
Im April 2017 wurde ein Patch in Safari zusammengeführt, sodass er mit den anderen Browsern übereinstimmt. Wird wahrscheinlich in Safari 11 landen
Sandstrom
2
Ich kann bestätigen, dass dies in Safari iOS 11 behoben wurde. Getestetes privates Surfen + sessionStorage.setItem () und dann sessionStorage.getItem () erfolgreich auf iPhone6 ​​und iPhone8.
Kevin Gaudin

Antworten:

372

Dies kann auftreten, wenn sich Safari im privaten Modus befindet. Beim privaten Surfen ist lokaler Speicher überhaupt nicht verfügbar.

Eine Lösung besteht darin, den Benutzer zu warnen, dass die App einen nicht privaten Modus benötigt, um zu funktionieren.

UPDATE: Dies wurde in Safari 11 behoben , sodass das Verhalten jetzt mit anderen Browsern übereinstimmt.

Cristian Dinu
quelle
4
Ihr Beitrag war heute (weniger als 24 Stunden später) für mich unglaublich hilfreich und aktuell. Als Referenz, hier ist, wie man privates Surfen ein- und
Nick
12
+1 hat mein Problem behoben. Ich habe if( typeof Storage != 'undefined' ) { ... }vor dem Laden und Speichern von Informationen nach LocalStorage ( ) gesucht , aber diesen Fehler erhalten. Es stellt sich heraus, dass Storagees auch dann noch definiert ist, wenn es unbrauchbar ist. Verwenden Sie von nun an try / catch, wenn ich LocalStorage verwende.
Stevendesu
Vielen Dank! Seltsamer Fehler durch Safari. Hätte informativer sein sollen. : D
Sunny R Gupta
2
Möglicherweise ist ab Safari Tech Preview 29 ein Fix eingegangen: "QuotaExceededError beim Speichern in localStorage im privaten Browsermodus oder in WebDriver-Sitzungen behoben". Siehe developer.apple.com/safari/technology-preview/release-notes
Marc Baumbach
1
Dies kann auch auftreten, wenn das Speicherlimit erreicht ist, was beispielsweise durch Speichern von Bildern leicht möglich ist.
Csalmeida
103

Wie in anderen Antworten erwähnt, erhalten Sie den QuotaExceededError im privaten Safari-Browsermodus unter iOS und OS X immer, wenn localStorage.setItem(oder sessionStorage.setItem) aufgerufen wird.

Eine Lösung besteht darin , in jedem Verwendungsfall einen Try / Catch- oder Modernizr-Check durchzuführen setItem.

Wenn Sie jedoch einen Shim möchten, der diesen Fehler einfach global verhindert, um zu verhindern, dass der Rest Ihres JavaScript beschädigt wird, können Sie Folgendes verwenden:

https://gist.github.com/philfreo/68ea3cd980d72383c951

// 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.');
    }
}
Philfreo
quelle
1
Warum das setItem zum Speicherobjekt hinzufügen, wenn Sie es trotzdem nicht verwenden können?
Nekromant
4
Der Sinn meines Snippets besteht darin, JS-Fehler beim Auslösen einfach zu ignorieren, wenn Ihre App im privaten Safari-Modus nicht vollständig beschädigt werden soll.
Philfreo
16

Ich verwende diese einfache Funktion, die zurückgibt trueoder false, um die Verfügbarkeit von localStorage zu testen:

isLocalStorageNameSupported = function() {
    var testKey = 'test', storage = window.sessionStorage;
    try {
        storage.setItem(testKey, '1');
        storage.removeItem(testKey);
        return true;
    } catch (error) {
        return false;
    }
}

Jetzt können Sie die localStorage.setItem()Verfügbarkeit testen, bevor Sie sie verwenden. Beispiel:

if ( isLocalStorageNameSupported() ) {
    // can use localStorage.setItem('item','value')
} else {
    // can't use localStorage.setItem('item','value')
}
DrewT
quelle
Habe ich etwas verpasst Warum window.sessionStoragewurde anstelle window.localStorageeiner Methode aufgerufen isLocalStorageNameSupported?
Ithar
@lthar - siehe die Dokumentation hier: w3schools.com/html/html5_webstorage.asp Am wichtigsten ist dieser Teil:HTML local storage provides two objects for storing data on the client: window.localStorage - stores data with no expiration date window.sessionStorage - stores data for one session (data is lost when the browser tab is closed)
DrewT
@DrewT, aber was ist der Unterschied in dieser Situation, wenn Sie Ihren Testschlüssel entfernen? Es spielt keine Rolle, wo ich meinen Testschlüssel speichern werde, wenn ich ihn löschen möchte. Liege ich falsch? Warum ist der Sitzungsspeicher besser als der lokale?
Vladyslav Turak
1
@TurakVladyslav Sie haben Recht, es gibt hier wirklich keinen Unterschied, außer dass die Verwendung sessionStoragees einfacher macht, Haltepunkte zu setzen, wenn Sie Ihre Entwicklung testen möchten. Es gibt kein wahres Argument, für das "besser" ist, und es ist hier wirklich nur eine persönliche Präferenz, die auf der Seite der Vorsicht irrt. Die Hauptsache ist, dass beide sessionStorageund localStoragebeide Implementierungen der HTML5-Webstorage-API sind.
DrewT
5

Ich habe zufällig das gleiche Problem in iOS 7 ausgeführt (bei einigen Geräten keine Simulatoren).

Es sieht so aus, als hätte Safari in iOS 7 ein niedrigeres Speicherkontingent, das anscheinend durch ein langes Verlaufsprotokoll erreicht wird.

Ich denke, die beste Vorgehensweise wird darin bestehen, die Ausnahme zu erwischen.

Das Modernizr-Projekt hat einen einfachen Patch. Sie sollten etwas Ähnliches ausprobieren: https://github.com/Modernizr/Modernizr/blob/master/feature-detects/storage/localstorage.js

defvol
quelle
3

Hier ist eine erweiterte Lösung, die auf der obigen Antwort von DrewT basiert und Cookies verwendet, wenn localStorage nicht verfügbar ist. Es verwendet Mozillas docCookies-Bibliothek :

function localStorageGet( pKey ) {
    if( localStorageSupported() ) {
        return localStorage[pKey];
    } else {
        return docCookies.getItem( 'localstorage.'+pKey );
    }
}

function localStorageSet( pKey, pValue ) {
    if( localStorageSupported() ) {
        localStorage[pKey] = pValue;
    } else {
        docCookies.setItem( 'localstorage.'+pKey, pValue );
    }
}

// global to cache value
var gStorageSupported = undefined;
function localStorageSupported() {
    var testKey = 'test', storage = window.sessionStorage;
    if( gStorageSupported === undefined ) {
        try {
            storage.setItem(testKey, '1');
            storage.removeItem(testKey);
            gStorageSupported = true;
        } catch (error) {
            gStorageSupported = false;
        }
    }
    return gStorageSupported;
}

Verwenden Sie in Ihrer Quelle einfach:

localStorageSet( 'foobar', 'yes' );
...
var foo = localStorageGet( 'foobar' );
...
Stickley
quelle
2

Wie bereits in anderen Antworten erläutert, löst Safari im privaten Browsermodus diese Ausnahme immer aus , wenn versucht wird, Daten mit zu speichern localStorage.setItem().

Um dies zu beheben, habe ich einen gefälschten localStorage geschrieben, der localStorage nachahmt, sowohl Methoden als auch Ereignisse.

Gefälschter localStorage: https://gist.github.com/engelfrost/fd707819658f72b42f55

Dies ist wahrscheinlich keine gute allgemeine Lösung für das Problem. Dies war eine gute Lösung für mein Szenario, in dem die Alternative darin besteht, eine bereits vorhandene Anwendung grundlegend neu zu schreiben.

Josef Engelfrost
quelle
Was genau behebt es? Es bleibt nichts bestehen, also was ist der Sinn?
Esben Skov Pedersen
1
Es "repariert" Safari im privaten Browsermodus. (Dies ist in meiner Antwort nicht klar, danke, dass Sie darauf hingewiesen haben. Ich werde meine Antwort bearbeiten.) Im privaten Browsermodus soll nichts beibehalten werden, daher ist das Nichtbestehen hier kein relevantes Problem. Für mich wurde dadurch behoben, dass Benutzer eine bereits vorhandene Anwendung ohne größere Umschreibungen ausführen können, selbst wenn sie sich in Safari im privaten Browsermodus befinden.
Josef Engelfrost
2

Update (01.11.2016)

Ich habe AmplifyJS verwendet, um dieses Problem zu umgehen. Bei Safari in Private Browsing wurde jedoch auf einen speicherbasierten Speicher zurückgegriffen. In meinem Fall war dies nicht angemessen, da der Speicher beim Aktualisieren gelöscht wird, auch wenn sich der Benutzer noch im privaten Browser befindet.

Außerdem habe ich eine Reihe von Benutzern bemerkt, die unter iOS Safari immer im privaten Modus surfen. Aus diesem Grund ist es für Safari ein besserer Fallback, Cookies zu verwenden (falls verfügbar). Standardmäßig sind Cookies auch beim privaten Surfen weiterhin verfügbar. Natürlich werden sie beim Verlassen des privaten Browsings gelöscht, aber beim Aktualisieren werden sie nicht gelöscht.

Ich habe die lokale Speicher-Fallback- Bibliothek gefunden. Aus der Dokumentation:

Zweck

Bei Browsereinstellungen wie "Private Browsing" ist es selbst in neueren Browsern zu einem Problem geworden, sich auf ein funktionierendes window.localStorage zu verlassen. Auch wenn es möglicherweise vorhanden ist, werden beim Versuch, setItem oder getItem zu verwenden, Ausnahmen ausgelöst. Dieses Modul führt entsprechende Überprüfungen durch, um festzustellen, welcher Browserspeichermechanismus möglicherweise verfügbar ist, und macht ihn dann verfügbar. Es verwendet dieselbe API wie localStorage, daher sollte es in den meisten Fällen als Drop-In-Ersatz fungieren.

Vorsicht vor den Fallstricken:

  • CookieStorage hat Speicherbeschränkungen. Sei hier vorsichtig.
  • MemoryStorage bleibt zwischen dem Laden der Seite nicht bestehen. Dies ist mehr oder weniger eine Lücke, um Seitenabstürze zu verhindern, kann jedoch für Websites ausreichen, die keine vollständigen Seitenladevorgänge ausführen.

TL; DR:

Verwenden Sie Local-Storage-Fallback (einheitliche API mit .getItem(prop)und .setItem(prop, val)):

Überprüfen und verwenden Sie den entsprechenden Speicheradapter für den Browser (localStorage, sessionStorage, Cookies, Speicher).

Ursprüngliche Antwort

Eine mögliche Problemumgehung besteht darin, die Speichermethode zu ändern, um frühere Antworten zu ergänzen. Es gibt einige Bibliotheken wie AmplifyJS und PersistJS, die helfen können. Beide Bibliotheken ermöglichen dauerhaften clientseitigen Speicher über mehrere Backends.

Für AmplifyJS

lokaler Speicher

  • IE 8+
  • Firefox 3.5+
  • Safari 4+
  • Chrom
  • Opera 10.5+
  • iPhone 2+
  • Android 2+

sessionStorage

  • IE 8+
  • Firefox 2+
  • Safari 4+
  • Chrom
  • Opera 10.5+
  • iPhone 2+
  • Android 2+

globalStorage

  • Firefox 2+

Benutzerdaten

  • IE 5 - 7
  • userData existiert auch in neueren Versionen von IE, aber aufgrund von Macken in der Implementierung von IE 9 registrieren wir userData nicht, wenn localStorage unterstützt wird.

Erinnerung

  • Ein speicherinterner Speicher wird als Fallback bereitgestellt, wenn keiner der anderen Speichertypen verfügbar ist.

Für PersistentJS

  • Flash: Dauerhafter Flash 8-Speicher.
  • Zahnräder: Google Gears-basierter persistenter Speicher.
  • localstorage: HTML5-Entwurfsspeicher.
  • globalstorage: HTML5-Entwurfsspeicher (alte Spezifikation).
  • dh: Verhalten der Internet Explorer-Benutzerdaten.
  • Cookie: Cookie-basierter persistenter Speicher.

Sie bieten eine Abstraktionsschicht, sodass Sie sich keine Gedanken über die Auswahl des Speichertyps machen müssen. Beachten Sie jedoch, dass es je nach Speichertyp einige Einschränkungen (z. B. Größenbeschränkungen) geben kann. Im Moment verwende ich AmplifyJS, aber ich muss noch einige Tests unter iOS 7 / Safari / etc. Durchführen. um zu sehen, ob es das Problem tatsächlich löst.

Jonathan Alzetta
quelle
Herausgeber John: Mir ist klar, dass Sie und Jonathan Alzetta wahrscheinlich dasselbe Konto haben und Sie nur versuchen, Ihre Antwort zu verbessern. Wenn dies jedoch der Fall ist, sollten Sie sich wirklich als Jonathan Alzetta anmelden und diese Antwort bearbeiten, damit sie nicht durchgeht die Überprüfungswarteschlange. Stellen Sie Ihr Konto bei Bedarf wieder her.
DavidS
1

Im April 2017 wurde ein Patch in Safari zusammengeführt, sodass er mit den anderen Browsern übereinstimmt. Dies wurde mit Safari 11 veröffentlicht.

https://bugs.webkit.org/show_bug.cgi?id=157010

Sandstrom
quelle
0

Diese Frage und Antwort hat mir geholfen, ein bestimmtes Problem bei der Anmeldung neuer Benutzer in Parse zu lösen.

Da die Funktion signUp (attrs, options) lokalen Speicher verwendet, um die Sitzung beizubehalten, wird im privaten Browsermodus ein Benutzer mit der Meldung "QuotaExceededError: DOM-Ausnahme 22: Es wurde versucht, dem Speicher etwas hinzuzufügen, das das Kontingent überschreitet". Ausnahme und die Erfolgs- / Fehlerfunktionen werden niemals aufgerufen.

In meinem Fall schien es, da die Fehlerfunktion nie aufgerufen wird, zunächst ein Problem beim Auslösen des Klickereignisses beim Senden oder der Weiterleitung zu sein, die bei erfolgreichem Anmelden definiert wurde.

Das Hinzufügen einer Warnung für Benutzer hat das Problem behoben.

Analysieren Sie die Javascript SDK-Referenz https://parse.com/docs/js/api/classes/Parse.User.html#methods_signUp

Registriert einen neuen Benutzer mit einem Benutzernamen (oder einer E-Mail) und einem Passwort. Dadurch wird ein neuer Parse.User auf dem Server erstellt und die Sitzung in localStorage beibehalten, sodass Sie über {@link #current} auf den Benutzer zugreifen können.

Clayostrom
quelle