QuotaExceededError: DOM исключение 22: была предпринята попытка добавить что-то в хранилище, превышающее квоту

использование LocalStorage на iPhone с iOS 7 выдает эту ошибку. Я искал resolvant, но, учитывая, что я даже не просматриваю в частном порядке, ничего не имеет значения.

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

у кого-нибудь была такая же проблема, только им повезло ее исправить? Должен ли я переключить свой метод хранения?

Я попытался отладить его, сохранив только несколько строк информации, но безрезультатно. Я использовал стандарт сохранить.

9 ответов


Это может произойти, когда Safari находится в частном режиме просмотра. В то время как в частном просмотре локальное хранилище недоступно вообще.

одним из решений является предупреждение пользователя о том, что приложение нуждается в режиме non-private для работы.

UPDATE: это было исправлено в сафари 11, поэтому поведение теперь выровнено с другими браузерами.


как упоминалось в других ответах, вы всегда получите 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.');
    }
}

я использую эту простую функцию, которая возвращает 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')
}

я случайно столкнулся с той же проблемой в iOS 7 (С некоторыми устройствами нет симуляторов).

похоже, что Safari в iOS 7 имеет более низкую квоту хранения, которая, по-видимому, достигается благодаря длинному журналу истории.

Я думаю, что лучшей практикой будет поймать исключение.

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


вот расширенное решение, основанное на ответе DrewT выше, которое использует куки, если localStorage недоступен. Он использует Mozilla библиотека docCookies:

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

Как уже было сказано в других ответах, в режиме приватного просмотра сафари всегда бросить это исключение при попытке сохранить данные с localStorage.setItem() .

чтобы исправить это, я написал поддельный localStorage, который имитирует localStorage, как методы, так и события.

поддельные localStorage:https://gist.github.com/engelfrost/fd707819658f72b42f55

это, вероятно, не является хорошим общим решением проблемы. Это было хорошее решение для моего сценария, где альтернативой была бы большая переписка в уже существующее приложение.


обновление (2016-11-01)

я использовал AmplifyJS, упомянутый ниже, чтобы обойти эту проблему. Однако для Safari в частном просмотре он возвращался к хранилищу на основе памяти. В моем случае это было неуместно, потому что это означает, что хранилище очищается при обновлении, даже если пользователь все еще находится в частном просмотре.

кроме того, я заметил ряд пользователей, которые всегда просматривают в частном режиме на iOS Safari. По этой причине лучшим резервным вариантом для Safari является используйте cookies (если таковые имеются). По умолчанию cookies по-прежнему доступны даже в приватном просмотре. Конечно, они очищаются при выходе из частного просмотра, но они не очищаются при обновлении.

нашел локальное хранилище-резервный библиотека. Из документации:

цель

с настройками браузера, такими как" частный просмотр", стало проблемой полагаться на рабочее окно.хранилище localStorage, даже в новых браузерах. Даже хотя он может существовать, он будет создавать исключения при попытке использовать setItem или getItem. Этот модуль будет выполнять соответствующие проверки, чтобы увидеть, какой механизм хранения браузера может быть доступен, а затем выставить его. Он использует тот же API, что и localStorage, поэтому в большинстве случаев он должен работать как замена.

остерегайтесь gotchas:

  • CookieStorage имеет пределы хранения. Будь осторожен.
  • MemoryStorage не будет сохраняться между загрузка страниц. Это более или менее стоп-гэп для предотвращения сбоев страниц, но может быть достаточно для веб-сайтов, которые не выполняют полную загрузку страниц.

TL; DR:

использовать локальное хранилище-резервный (унифицированный API с .getItem(prop) и .setItem(prop, val)):

проверьте и используйте соответствующий адаптер хранения для браузера (localStorage, sessionStorage, cookies, memory)

оригинальный ответ

добавить на предыдущие ответы, одним из возможных обходных путей было бы изменение метода хранения. Есть несколько либрарий, таких как AmplifyJS и PersistJS, который может помочь. Обе библиотеки позволяют постоянное хранение на стороне клиента через несколько бэкэндов.

Для AmplifyJS

localStorage

  • IE 8+
  • Firefox 3.5+
  • Safari 4+
  • хром
  • Опера 10.5+
  • iPhone 2+
  • Android 2+

sessionStorage

  • IE 8+
  • Firefox 2+
  • Safari 4+
  • хром
  • Опера 10.5+
  • iPhone 2+
  • Android 2+

globalStorage

  • Firefox 2+

userData

  • т. е. 5 - 7
  • userData существует и в более новых версиях IE, но из-за причуд в реализации IE 9 мы не регистрируем userData, если localStorage поддерживаемый.

  • хранилище в памяти предоставляется в качестве резервного, если ни один из других типов хранения не доступны.

Для PersistentJS

  • flash: Flash 8 постоянное хранилище.
  • шестерни: Google Постоянное хранение на основе шестеренок.
  • localstorage: хранение проекта HTML5.
  • globalstorage: хранение проекта HTML5 (старая спецификация).
  • т. е.: Интернет Эксплорер, например, userdata поведения.
  • cookie: постоянное хранение на основе файлов Cookie.

они предлагают слой абстракции, поэтому вам не нужно беспокоиться о выборе типа хранения. Имейте в виду, что могут быть некоторые ограничения (например, ограничения размера) в зависимости от однако тип хранения. Прямо сейчас, я использую AmplifyJS, но мне все еще нужно сделать еще несколько тестов на iOS 7/Safari/etc. чтобы увидеть, действительно ли это решает проблему.


в апреле 2017 патч был объединен в Safari, поэтому он выровнен с другими браузерами. Это было выпущено с Safari 11.

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


этот вопрос и ответ помог мне решить конкретную проблему с регистрацией новых пользователей в Parse.

поскольку функция регистрации (attrs, options) использует локальное хранилище для сохранения сеанса, если пользователь находится в режиме частного просмотра, он выдает "QuotaExceededError: DOM исключение 22: была сделана попытка добавить что-то в хранилище, которое превысило квоту."исключение и функции успеха / ошибки никогда не вызываются.

в моем случае, потому что функция ошибки никогда не вызывал его изначально, казалось, проблема с запуском события click на submit или перенаправление, определенное на успех регистрации.

включая предупреждение для пользователей решена проблема.

синтаксический анализ Javascript SDK Reference https://parse.com/docs/js/api/classes/Parse.User.html#methods_signUp

регистрирует нового пользователя с именем пользователя (или электронной почтой) и паролем. Это создаст новый синтаксический анализ.Пользователь на сервере, а также сохранить сеанс в localStorage чтобы вы могли получить доступ к пользователю с помощью {@link #current}.