QuotaExceededError: exception Dom 22: une tentative a été effectuée pour ajouter quelque chose au stockage dépassant le quota

219

L'utilisation de LocalStorage sur iPhone avec iOS 7 génère cette erreur. J'ai cherché un résolvant, mais étant donné que je ne navigue même pas en privé, rien n'est pertinent.

Je ne comprends pas pourquoi localStorage serait désactivé par défaut dans iOS 7, mais il semble que ce soit le cas? J'ai également testé sur d'autres sites, mais sans succès. J'ai même essayé de le tester en utilisant ce site Web: http://arty.name/localstorage.html , mais il ne semble pas que cela enregistre quoi que ce soit pour une raison étrange.

Quelqu'un a-t-il eu le même problème, seulement ils ont eu de la chance de le résoudre? Dois-je changer de méthode de stockage?

J'ai essayé de le déboguer en ne stockant que quelques lignes d'informations, mais en vain. J'ai utilisé la localStorage.setItem()fonction standard pour enregistrer.

Nict
la source
2
Cela signifie généralement que vous avez essayé de stocker quelque chose dont la taille dépassait l'espace de stockage disponible. Quel navigateur utilisez-vous (Safari, Chrome, etc.)? Pouvez-vous partager un peu plus le code que vous avez utilisé et si possible les données que vous essayez de stocker.
3
Cela devrait être considéré comme un bogue ou un problème du côté Safari. Cela n'a pas de sens que vous ne puissiez pas utiliser localStorage en mode incognito ...
Maksim Luzik
Utilisez une fonction de détection qui teste ce problème spécifique . Si le stockage n'est pas disponible, envisagez de caler localStorage avec memoryStorage . mentions légales: Je suis l'auteur des packages liés
Stijn de Witt
1
En avril 2017, un correctif a été fusionné dans Safari, il s'est donc aligné sur les autres navigateurs. Atterrira
sandstrom
2
Je peux confirmer que cela a été corrigé dans Safari iOS 11. Navigation privée testée + sessionStorage.setItem () puis sessionStorage.getItem () avec succès sur iPhone6 ​​et iPhone8.
Kevin Gaudin

Réponses:

372

Cela peut se produire lorsque Safari est en navigation en mode privé. En navigation privée, le stockage local n'est pas disponible du tout.

Une solution consiste à avertir l'utilisateur que l'application a besoin d'un mode non privé pour fonctionner.

MISE À JOUR: Cela a été corrigé dans Safari 11 , donc le comportement est maintenant aligné avec les autres navigateurs.

Cristian Dinu
la source
4
Votre message a été incroyablement utile et opportun pour moi aujourd'hui (moins de 24 heures plus tard). Pour référence, voici comment activer / désactiver la navigation privée: imore.com/how-use-private-browsing-ios-7-safari
Nick
12
+1 a résolu mon problème. Je vérifiais l'existence de LocalStorage ( if( typeof Storage != 'undefined' ) { ... }) avant d'essayer de charger et d'enregistrer des informations mais d'obtenir cette erreur. S'avère Storageest toujours défini même lorsqu'il est inutilisable. Utilisation de try / catch à partir de maintenant chaque fois que j'utilise LocalStorage.
stevendesu
Merci! Erreur étrange par safari. Aurait dû être plus informatif. : D
Sunny R Gupta
2
Un correctif peut être entrant à partir de Safari Tech Preview 29: "Correction de QuotaExceededError lors de l'enregistrement sur localStorage en mode de navigation privée ou des sessions WebDriver". Voir developer.apple.com/safari/technology-preview/release-notes
Marc Baumbach
1
Cela peut également se produire si la limite de stockage est atteinte, ce qui peut être facilement fait en enregistrant des images par exemple.
csalmeida
103

Comme mentionné dans d'autres réponses, vous obtiendrez toujours QuotaExceededError en mode navigateur privé Safari sur iOS et OS X lorsque localStorage.setItem(ou sessionStorage.setItem) est appelé.

Une solution consiste à faire une vérification try / catch ou Modernizr dans chaque instance d'utilisation setItem.

Cependant, si vous voulez un shim qui arrête simplement globalement cette erreur, pour empêcher le reste de votre JavaScript de se casser, vous pouvez utiliser ceci:

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
la source
1
Pourquoi ajouter le setItem à l'objet Storage si vous ne pourrez pas l'utiliser quand même?
Nécromancien
4
Le point de mon extrait est d'ignorer simplement les erreurs JS d'être lancées si vous voulez que votre application ne soit pas totalement cassée en mode privé Safari.
philfreo
16

J'utilise cette fonction simple, qui renvoie trueou false, pour tester la disponibilité de localStorage:

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

Vous pouvez maintenant tester la localStorage.setItem()disponibilité avant de l'utiliser. Exemple:

if ( isLocalStorageNameSupported() ) {
    // can use localStorage.setItem('item','value')
} else {
    // can't use localStorage.setItem('item','value')
}
DrewT
la source
Ai-je raté quelque chose? Pourquoi est-il window.sessionStorageutilisé à la place d' window.localStorageune méthode appelée isLocalStorageNameSupported?
Ithar
@lthar - voir la documentation ici: w3schools.com/html/html5_webstorage.asp Surtout cette partie: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, mais quelle est la différence dans cette situation si vous supprimez votre clé de test? Peu importe où je vais stocker ma clé de test si je vais la supprimer. Ai-je tort? Pourquoi le stockage de session est-il meilleur que le local?
Vladyslav Turak
1
@TurakVladyslav vous avez raison, il n'y a vraiment aucune différence ici, sauf que l'utilisation le sessionStoragerend plus facile à gérer pour définir des points d'arrêt si vous souhaitez tester votre développement. Il n'y a pas de véritable argument pour lequel "mieux" et c'est vraiment juste une préférence personnelle ici qui pèche par excès de prudence. La principale chose à noter est que les deux sessionStorageet localStoragesont les deux implémentations de l'API HTML5 webstorage.
DrewT
5

Il m'est arrivé de courir avec le même problème dans iOS 7 (avec certains appareils sans simulateurs).

Il semble que Safari dans iOS 7 ait un quota de stockage inférieur, qui est apparemment atteint grâce à un long historique.

J'imagine que la meilleure pratique sera d'attraper l'exception.

Le projet Modernizr a un correctif facile, vous devriez essayer quelque chose de similaire: https://github.com/Modernizr/Modernizr/blob/master/feature-detects/storage/localstorage.js

defvol
la source
3

Voici une solution étendue basée sur la réponse de DrewT ci-dessus qui utilise des cookies si localStorage n'est pas disponible. Il utilise la bibliothèque docCookies de Mozilla :

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;
}

Dans votre source, utilisez simplement:

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

Comme déjà expliqué dans d'autres réponses, en mode de navigation privée, Safari lève toujours cette exception lorsque vous essayez d'enregistrer des données avec localStorage.setItem().

Pour résoudre ce problème, j'ai écrit un faux localStorage qui imite localStorage, à la fois les méthodes et les événements.

Fake localStorage: https://gist.github.com/engelfrost/fd707819658f72b42f55

Ce n'est probablement pas une bonne solution générale au problème. C'était une bonne solution pour mon scénario, où l'alternative serait une réécriture majeure sur une application déjà existante.

Josef Engelfrost
la source
Que résout-il exactement? Il ne persiste rien, alors à quoi ça sert?
Esben Skov Pedersen
1
Il "corrige" Safari en mode de navigation privée. (Ce n'est pas clair dans ma réponse, merci de l'avoir signalé. Je vais modifier ma réponse). Rien n'est censé être persisté en mode de navigation privée, donc ne pas persister n'est pas un problème pertinent ici. Ce que cela a résolu pour moi était de permettre aux utilisateurs d'exécuter une application déjà existante, sans réécriture majeure, même en mode de navigation privée dans Safari.
Josef Engelfrost
2

Mise à jour (2016-11-01)

J'utilisais AmplifyJS mentionné ci-dessous pour contourner ce problème. Cependant, pour Safari en navigation privée, il retombait sur un stockage basé sur la mémoire. Dans mon cas, cela n'était pas approprié car cela signifie que le stockage est effacé lors de l'actualisation, même si l'utilisateur est toujours en navigation privée.

De plus, j'ai remarqué un certain nombre d'utilisateurs qui naviguent toujours en mode privé sur iOS Safari. Pour cette raison, une meilleure solution de rechange pour Safari consiste à utiliser des cookies (si disponibles). Par défaut, les cookies sont toujours accessibles même en navigation privée. Bien sûr, ils sont effacés lorsque vous quittez la navigation privée, mais ils ne sont pas effacés lors de l'actualisation.

J'ai trouvé la bibliothèque local-storage-fallback . De la documentation:

Objectif

Avec des paramètres de navigateur tels que "Navigation privée", il est devenu difficile de compter sur un window.localStorage fonctionnel, même dans les navigateurs plus récents. Même s'il peut exister, il lèvera des exceptions lors de la tentative d'utilisation de setItem ou getItem. Ce module exécutera les vérifications appropriées pour voir quel mécanisme de stockage du navigateur pourrait être disponible, puis l'exposera. Il utilise la même API que localStorage, il devrait donc fonctionner comme remplacement direct dans la plupart des cas.

Méfiez-vous des gotchas:

  • CookieStorage a des limites de stockage. Faites attention ici.
  • MemoryStorage ne persistera pas entre les chargements de page. Il s'agit plus ou moins d'un espace pour éviter les plantages de pages, mais cela peut être suffisant pour les sites Web qui ne font pas de chargement de page complète.

TL; DR:

Utilisez local-storage-fallback (API unifiée avec .getItem(prop)et .setItem(prop, val)):

Vérifiez et utilisez l'adaptateur de stockage approprié pour le navigateur (localStorage, sessionStorage, cookies, mémoire)

Réponse originale

Pour ajouter aux réponses précédentes, une solution de contournement possible serait de changer la méthode de stockage. Il existe quelques bibliothèques telles que AmplifyJS et PersistJS qui peuvent vous aider. Les deux bibliothèques permettent un stockage persistant côté client via plusieurs backends.

Pour AmplifyJS

stockage local

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

sessionStorage

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

globalStorage

  • Firefox 2+

données d'utilisateur

  • IE 5 - 7
  • userData existe également dans les versions plus récentes d'IE, mais en raison de bizarreries dans l'implémentation d'IE 9, nous n'enregistrons pas userData si localStorage est pris en charge.

Mémoire

  • Un stockage en mémoire est fourni comme solution de secours si aucun des autres types de stockage n'est disponible.

Pour PersistentJS

  • flash: stockage persistant Flash 8.
  • gears: stockage persistant basé sur Google Gears.
  • localstorage: stockage de brouillons HTML5.
  • globalstorage: stockage de brouillon HTML5 (ancienne spécification).
  • c'est-à-dire: les comportements des données utilisateur d'Internet Explorer.
  • cookie: stockage persistant basé sur les cookies.

Ils offrent une couche d'abstraction afin que vous n'ayez pas à vous soucier du choix du type de stockage. Gardez à l'esprit qu'il peut y avoir des limitations (telles que des limites de taille) en fonction du type de stockage. En ce moment, j'utilise AmplifyJS, mais je dois encore faire des tests supplémentaires sur iOS 7 / Safari / etc. pour voir si cela résout réellement le problème.

Jonathan Alzetta
la source
Rédacteur en chef John: Je me rends compte que vous et Jonathan Alzetta êtes probablement le même compte et que vous essayez simplement d'améliorer votre réponse, mais si c'est le cas, vous devez vraiment vous connecter en tant que Jonathan Alzetta et modifier cette réponse, puis elle ne passera pas par la file d'attente de révision. Récupérez votre compte si vous en avez besoin.
DavidS
0

Cette question et cette réponse m'ont aidé à résoudre un problème spécifique lié à l'inscription de nouveaux utilisateurs dans Parse.

Étant donné que la fonction signUp (attrs, options) utilise le stockage local pour conserver la session, si un utilisateur est en mode de navigation privée, il renvoie «QuotaExceededError: DOM Exception 22: une tentative a été effectuée pour ajouter quelque chose au stockage qui dépasse le quota». exception et les fonctions succès / erreur ne sont jamais appelées.

Dans mon cas, parce que la fonction d'erreur n'est jamais appelée, elle semblait initialement être un problème avec le déclenchement de l'événement de clic sur la soumission ou la redirection définie en cas de succès de l'inscription.

L'inclusion d'un avertissement pour les utilisateurs a résolu le problème.

Parse Javascript SDK Reference https://parse.com/docs/js/api/classes/Parse.User.html#methods_signUp

Enregistre un nouvel utilisateur avec un nom d'utilisateur (ou e-mail) et un mot de passe. Cela créera un nouveau Parse.User sur le serveur et conservera également la session dans localStorage afin que vous puissiez accéder à l'utilisateur en utilisant {@link #current}.

clayostrom
la source