QuotaExceededError: Dom виняток 22: Була зроблена спроба додати щось у сховище, що перевищило квоту


219

Використання LocalStorage на iPhone з iOS 7 призводить до цієї помилки. Я роздивлявся резолюцію, але, вважаючи, що навіть не переглядаю приватно, нічого не стосується.

Я не розумію, чому localStorage буде відключено за замовчуванням в iOS 7, але здається, що так? Я тестував і на інших веб-сайтах, але не пощастило. Я навіть спробував тестувати його за допомогою цього веб-сайту: http://arty.name/localstorage.html , але, схоже, це щось не економить з якихось дивних причин.

Хтось мав ту саму проблему, тільки вони пощастили її виправити? Чи слід переключити спосіб зберігання?

Я намагався налагодити це, зберігаючи лише кілька рядків інформації, але безрезультатно. Я використовував стандартну localStorage.setItem()функцію для збереження.


2
Зазвичай це означає, що ви намагалися зберігати щось із розміром, який перевищує доступний обсяг пам’яті. Який браузер ви використовуєте (Safari, Chrome тощо)? Чи можете ви поділитися трохи більше коду, який ви використовували, і, якщо можливо, даних, які ви намагаєтесь зберегти.

3
Це слід розглядати як помилку або проблему на стороні Safari. Немає сенсу, що ви не можете використовувати localStorage в режимі інкогніто ...
Максим Лузик

Використовуйте функцію виявлення тестів для цієї конкретної проблеми . Якщо пам’яті недоступне, розгляньте, як локальне зберігання зберігається пам’яттюStorage . відмова від відповідальності: Я є автором пов'язаних пакетів
Stijn de Witt

1
У квітні 2017 року патч було об'єднано в Safari, тому він узгоджувався з іншими браузерами. Ймовірно, приземлиться в Safari 11. bugs.webkit.org/show_bug.cgi?id=157010
пісок

2
Я можу підтвердити, що це було виправлено у Safari iOS 11. Тестоване приватне перегляд + sessionStorage.setItem (), а потім sessionStorage.getItem () успішно на iPhone6 ​​та iPhone8.
Кевін Гаудін

Відповіді:


372

Це може статися, коли Safari переглядає приватний режим. Перебуваючи в приватному веб-перегляді, локальне зберігання взагалі недоступне.

Одне рішення - попередити користувача, що для роботи додатку потрібен не приватний режим.

ОНОВЛЕННЯ: Це було виправлено в Safari 11 , тому поведінка тепер узгоджується з іншими браузерами.


4
Ваше повідомлення було просто неймовірно корисним та своєчасним для мене сьогодні (менше ніж через 24 години). Для довідки, ось як увімкнути / вимкнути приватне перегляд: imore.com/how-use-private-browsing-ios-7-safari
Nick

12
+1 вирішив мою проблему. Я перевіряв наявність LocalStorage ( if( typeof Storage != 'undefined' ) { ... }), перш ніж намагатися завантажити та зберегти інформацію, але отримав цю помилку. Виявляється, Storageвсе ще визначається, навіть коли це непридатно. Використовуючи спробувати / catch зараз, коли я використовую LocalStorage.
stevendesu

Дякую! Дивна помилка сафарі. Повинні були бути більш інформативними. : D
Сонячний Р Гупта

2
Виправлення може надходити за станом Safari Tech Preview 29: "Виправлений QuotaExceededError під час збереження до localStorage в режимі приватного перегляду чи сеансів WebDriver". Дивіться developer.apple.com/safari/technology-preview/release-notes
Марк Баумбах

1
Це також може статися, якщо буде досягнуто обмеження на зберігання, що може бути легко виконано, наприклад, збереженням зображень.
csalmeida

103

Як згадується в інших відповідях, ви завжди отримаєте QuotaExceededError в режимі приватного браузера Safari для iOS та OS X, коли localStorage.setItem(або sessionStorage.setItem) викликається.

Одне рішення - зробити спробу / ловити або перевірити Modernizr у кожному випадку використання setItem.

Однак, якщо ви хочете, щоб ця лайка просто глобально зупиняла скидання цієї помилки, щоб не допустити зламу решти вашого JavaScript, ви можете скористатися цим:

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.');
    }
}

1
Навіщо додавати setItem до об’єкта Storage, якщо ви все одно не зможете ним користуватися?
Некромант

4
Сенс мого фрагмента - просто ігнорувати помилки JS від їх викидання, якщо ви хочете, щоб ваша програма не була повністю порушена в приватному режимі Safari.
philfreo

16

Я використовую цю просту функцію, яка повертає trueабо false, щоб перевірити наявність доступності localStorage:

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

Тепер ви можете перевірити localStorage.setItem()наявність, перш ніж використовувати його. Приклад:

if ( isLocalStorageNameSupported() ) {
    // can use localStorage.setItem('item','value')
} else {
    // can't use localStorage.setItem('item','value')
}

Я щось пропустив? Чому window.sessionStorageвикористовується window.localStorageметод замість методу, який називається isLocalStorageNameSupported?
Ithar

@lthar - дивіться документацію тут: w3schools.com/html/html5_webstorage.asp Найголовніше це частина: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, але яка різниця в цій ситуації, якщо ви вилучите тестовий ключ? Не має значення, де я зберігатиму свій тестовий ключ, якщо я збираюся його видалити. Я помиляюся? Чому сховище сеансу краще, ніж місцеве?
Владислав Турак

1
@TurakVladyslav ви праві, тут насправді немає різниці, окрім того, що використання sessionStorageробить його більш керованим для встановлення точок прориву, якщо ви хочете перевірити свою розробку. Немає правдивого аргументу, щодо якого «краще», і це насправді лише особисті переваги, які помиляються на стороні обережності. Головне , щоб відзначити , що обидва sessionStorageі localStorageобидва реалізацій HTML5 Webstorage API.
DrewT

5

Мені траплялося запускати ту саму проблему в iOS 7 (на деяких пристроях немає тренажерів).

Схоже, що Safari в iOS 7 має меншу квоту зберігання, яка, очевидно, досягається завдяки довгому журналу історії.

Думаю, найкращою практикою буде вилов винятку.

Проект Modernizr має простий патч, ви можете спробувати щось подібне: https://github.com/Modernizr/Modernizr/blob/master/feature-detects/storage/localstorage.js


3

Ось розширене рішення, засноване на відповіді DrewT вище, що використовує файли cookie, якщо localStorage недоступний. Він використовує бібліотеку docCookies 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;
}

У своєму джерелі просто використовуйте:

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

2

Як уже було пояснено в інших відповідях, коли в режимі приватного перегляду Safari завжди викидає це виняток, намагаючись зберегти дані localStorage.setItem().

Щоб виправити це, я написав підроблений localStorage, який імітує localStorage, як методи, так і події.

Підроблені локальні сховища: https://gist.github.com/engelfrost/fd707819658f72b42f55

Це, мабуть, не гарне загальне рішення проблеми. Це було гарним рішенням для мого сценарію, де альтернатива буде серйозним перезаписом до вже існуючої програми.


Що саме це фіксує? Це нічого не зберігається, тож у чому справа?
Есбен Сков Педерсен

1
Він "виправляє" Safari в режимі приватного перегляду. (Це не ясно в моїй відповіді, дякую, що вказав на це. Я редагую свою відповідь). Нічого не повинно зберігатися, коли в режимі приватного перегляду не існує, тому не збереження не є актуальною проблемою тут. Для мене це виправлено - дозволити користувачам запускати вже наявну програму без великих перезаписів, навіть коли в режимі приватного перегляду в Safari.
Йозеф Енгельфрост

2

Оновлення (2016-11-01)

Я використовував згаданий нижче AmplifyJS, щоб вирішити цю проблему. Однак для Safari в приватному перегляді він повертався до пам’яті на основі пам’яті. У моєму випадку це було недоцільно, оскільки це означає, що зберігання очищено під час оновлення, навіть якщо користувач все ще перебуває в приватному веб-перегляді.

Також я помітив декілька користувачів, які постійно переглядають у приватному режимі на iOS Safari. З цієї причини кращим резервом для Safari є використання файлів cookie (якщо вони доступні). За замовчуванням файли cookie все ще доступні навіть у приватному веб-перегляді. Звичайно, вони видаляються під час виходу з приватного веб-перегляду, але вони не видаляються під час оновлення.

Я знайшов бібліотеку локального зберігання та резервного копіювання . З документації:

Призначення

З налаштуваннями браузера, як-от "Private Browsing", стало покладатися на робочий window.localStorage, навіть у новіших браузерах. Навіть незважаючи на те, що він може існувати, він викине винятки при спробі використання setItem або getItem. Цей модуль буде виконувати відповідні перевірки, щоб побачити, який механізм зберігання браузера може бути доступний, а потім викрити його. Він використовує той же API, що і localStorage, тому він повинен працювати як заміна, що випадає, у більшості випадків.

Обережно:

  • CookieStorage має обмеження на зберігання. Будьте обережні тут.
  • MemoryStorage не зберігатиметься між завантаженнями сторінки. Це більш-менш стоп-пробіл для запобігання збоїв сторінки, але може бути достатньо для веб-сайтів, які не завантажують повну сторінку.

TL; DR:

Використовуйте локальне зберігання (резервний запас) (уніфікований API з .getItem(prop)та .setItem(prop, val)):

Перевірте та використовуйте відповідний адаптер пам’яті для браузера (localStorage, sessionStorage, cookies, memory)

Оригінальна відповідь

Щоб додати попередні відповіді, одним із можливих рішень було б змінити спосіб зберігання. Є кілька бібліотек, таких як AmplifyJS та PersistJS, які можуть допомогти. Обидві конвеєри дозволяють зберігати на базі клієнта постійне зберігання через декілька програм.

Для AmplifyJS

місцеві магазини

  • IE 8+
  • Firefox 3.5+
  • Сафарі 4+
  • Хром
  • Opera 10.5+
  • iPhone 2+
  • Android 2+

сховище

  • IE 8+
  • Firefox 2+
  • Сафарі 4+
  • Хром
  • Opera 10.5+
  • iPhone 2+
  • Android 2+

globalStorage

  • Firefox 2+

userData

  • IE 5 - 7
  • userData також існує в нових версіях IE, але через примхи у впровадженні IE 9 ми не реєструємо userData, якщо підтримується localStorage.

пам'ять

  • Зберігання в пам'яті надається як резервний запас, якщо жоден з інших типів пам’яті недоступний.

Для стійкихJS

  • спалах: пам'ять, що зберігається у спалах 8.
  • gears: постійне зберігання на основі Google Gears.
  • localstorage: сховище чернетки HTML5.
  • globalstorage: сховище чернетки HTML5 (стара специфікація).
  • тобто: поведінка даних про Internet Explorer.
  • cookie: постійне зберігання на основі файлів cookie.

Вони пропонують шар абстракції, тому вам не доведеться турбуватися про вибір типу зберігання. Майте на увазі, що можуть бути деякі обмеження (наприклад, обмеження розміру) залежно від типу пам’яті. Зараз я використовую AmplifyJS, але мені ще належить зробити ще кілька тестувань на iOS 7 / Safari / тощо. щоб побачити, чи реально вона вирішує проблему.


Редактор Джон: Я розумію, що ви і Джонатан Альзетта, мабуть, однаковий обліковий запис, і ви просто намагаєтесь покращити свою відповідь, але якщо так, вам слід справді увійти як Джонатан Альзетта і відредагувати цю відповідь, і тоді вона не пройде черга огляду Відновіть свій рахунок, якщо вам потрібно.
DavidS


0

Це запитання та відповідь допомогли мені вирішити конкретну проблему із підпискою нових користувачів у Parse.

Оскільки функція signUp (attrs, options) використовує локальний сховище для збереження сеансу, якщо користувач перебуває в режимі приватного перегляду, він кидає "QuotaExceededError: DOM Виняток 22: Була зроблена спроба додати щось у сховище, що перевищило квоту". Виняток і функції успіху / помилки ніколи не викликаються.

У моєму випадку, оскільки функція помилки ніколи не викликається, вона спочатку виявилася проблемою із запуском події клацання при поданні або переспрямуванням, визначеним при успіху реєстрації.

У тому числі попередження для користувачів вирішено проблему.

Проаналізувати посилання на SDK JavaScript JavaScript https://parse.com/docs/js/api/classes/Parse.User.html#methods_signUp

Підпишіться на нового користувача з ім'ям користувача (або електронною поштою) та паролем. Це створить новий Parse.User на сервері, а також збереже сеанс у localStorage, щоб ви могли отримати доступ до користувача за допомогою {@link #current}.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.