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

176

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

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

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

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

  • 2
    Обычно это означает, что вы пытались сохранить что-то с размером, превышающим доступное место для хранения. Какой браузер вы используете (Safari, Chrome и т. Д.)? Можете ли вы поделиться немного больше кода, который вы использовали, и, если возможно, данные, которые вы пытаетесь сохранить.
  • 3
    Это следует рассматривать как ошибку или проблему на стороне Safari. Это не имеет смысла, что вы не можете использовать localStorage в режиме инкогнито ...
Показать ещё 4 комментария
Теги:
iphone
local-storage

9 ответов

333
Лучший ответ

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

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

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

  • 4
    Ваш пост был просто невероятно полезным и своевременным для меня сегодня (менее чем через 24 часа). Для справки вот как включить / выключить приватный просмотр: imore.com/how-use-private-browsing-ios-7-safari
  • 11
    +1 исправил мою проблему. Я проверял существование LocalStorage ( if( typeof Storage != 'undefined' ) { ... } ), прежде чем пытаться загрузить и сохранить информацию, но получил эту ошибку. Оказывается, Storage все еще определяется, даже когда оно непригодно для использования. Используя try / catch, теперь я использую LocalStorage.
Показать ещё 7 комментариев
96

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

Одним из решений является попытка try/catch или Проверка модернизма в каждом случае использования 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, если вы все равно не сможете его использовать?
  • 2
    Смысл моего фрагмента в том, чтобы просто игнорировать ошибки JS, возникающие при их выдаче, если вы хотите, чтобы ваше приложение не полностью ломалось в приватном режиме Safari.
13

Я использую эту простую функцию, которая возвращает 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')
}
  • 0
    Я что-то пропустил? Почему window.sessionStorage используется вместо window.localStorage для метода isLocalStorageNameSupported ?
  • 0
    @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)
Показать ещё 2 комментария
4

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

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

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

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

3

Вот расширенное решение на основе ответа DrewT выше, в котором используются файлы cookie, если 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' );
...
2

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

Для AmplifyJS

LocalStorage

  • 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 +

USERDATA

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

памяти

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

Для PersistentJS

  • flash: постоянное хранилище Flash 8.
  • gears: постоянное хранилище на основе Google Gears.
  • localstorage: хранилище черновиков HTML5.
  • globalstorage: хранилище черновиков HTML5 (старая спецификация).
  • то есть: поведение пользовательских данных в Internet Explorer.
  • cookie: постоянное хранилище на основе файлов cookie.

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

  • 0
    Редактор Джон: Я понимаю, что вы и Джонатан Алзетта, вероятно, являетесь одним и тем же аккаунтом, и вы просто пытаетесь улучшить свой ответ, но если это так, вам действительно нужно войти в систему как Джонатан Альзетта и отредактировать этот ответ, и тогда он не пройдет Очередь обзора. Восстановите свой аккаунт, если вам нужно.
2

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

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

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

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

  • 0
    Что именно это исправляет? Ничего не сохраняется, так какой в этом смысл?
  • 1
    Он «исправляет» Safari в режиме приватного просмотра. (Это не ясно в моем ответе, спасибо за указание на это. Я отредактирую свой ответ). Ничто не должно сохраняться в режиме приватного просмотра независимо, поэтому отсутствие сохранения не является здесь важной проблемой. Для меня это исправило то, что пользователи могли запускать уже существующее приложение без значительных перезаписей даже в режиме приватного просмотра в Safari.
1

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

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

0

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

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

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

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

Параметр Javascript SDK Reference https://parse.com/docs/js/api/classes/Parse.User.html#methods_signUp

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

Ещё вопросы

Сообщество Overcoder
Наверх
Меню