QuotaExceededError:Dom异常22:试图向存储中添加超出配额的内容


219

在iPhone和iOS 7上使用LocalStorage会引发此错误。我一直在寻找一种解决方案,但是考虑到我什至没有私下浏览,所以没有任何关系。

我不明白为什么默认情况下在iOS 7中会禁用localStorage,但似乎是这样吗?我也在其他网站上进行了测试,但是没有运气。我什至尝试使用以下网站对其进行测试:http : //arty.name/localstorage.html,但出于某种奇怪的原因,它似乎根本没有保存任何东西。

有没有人遇到过同样的问题,只有他们靠运气解决了吗?我应该切换存储方式吗?

我尝试通过仅存储几行信息来对它进行硬调试,但无济于事。我使用标准localStorage.setItem()功能保存。


2
通常,这意味着您尝试存储的大小超出了可用存储空间。您正在使用哪种浏览器(Safari,Chrome等)?您能否再分享一些您一直在使用的代码,并在可能的情况下尝试存储的数据。

3
这应该被视为Safari方面的错误或问题。您不能在隐身模式下使用localStorage是没有道理的……
Maksim Luzik

使用功能检测该特定问题的测试。如果存储不可用,请考虑使用memoryStorage填充 localStorage 。免责声明:我是链接软件包的作者
Stijn de Witt

1
2017年4月,一个补丁被合并到Safari中,因此与其他浏览器保持一致。可能会登陆Safari11。bugs.webkit.org/show_bug.cgi?id=157010
sandstrom

2
我可以确认此问题已在Safari iOS 11中得到修复。在iPhone6和iPhone8上成功测试了专用浏览+ sessionStorage.setItem(),然后sessionStorage.getItem()。
凯文·高丁

Answers:


372

当Safari处于私有模式下浏览时,可能会发生这种情况。在私人浏览中,本地存储根本不可用。

一种解决方案是警告用户该应用程序需要非私有模式才能运行。

更新:Safari 11中已修复此问题,因此该行为现在与其他浏览器一致。


4
今天(不到24小时),您的帖子对我来说是非常有用和及时的。作为参考,以下是打开/关闭私人浏览的方法:imore.com/how-use-private-browsing-ios-7-safari
Nick

12
+1解决了我的问题。if( typeof Storage != 'undefined' ) { ... }在尝试加载和保存信息之前,我正在检查是否存在LocalStorage(),但收到此错误。事实证明,Storage即使它不可用,它仍然被定义。从现在开始,每当我使用LocalStorage时都使用try / catch。
stevendesu 2014年

谢谢!Safari造成的奇怪错误。应该会提供更多信息。:D
Sunny R Gupta

2
自Safari Tech Preview 29起,可能会收到修复程序:“在私有浏览模式或WebDriver会话中保存到localStorage时,修复了QuotaExceededError”。参见developer.apple.com/safari/technology-preview/release-notes
Marc Baumbach

1
如果达到存储限制(例如可以通过保存图像轻松完成),也会发生这种情况。
csalmeida

103

如其他答案中所述,调用localStorage.setItem(或sessionStorage.setItem)时,在iOS和OS X上的Safari私有浏览器模式下,您始终会收到QuotaExceededError 。

一种解决方案是在使用的每个实例中进行try / catch或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
如果您不希望您的应用在Safari私有模式下被完全破坏,我的代码片段的目的就是简单地避免引发JS错误。
philfreo

16

我使用此简单函数(返回truefalse)来测试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
伊萨尔

@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 '16

@DrewT,但是如果您删除测试密钥,在这种情况下有什么区别?如果要删除测试密钥,将存储在哪里都无所谓。我错了吗?为什么会话存储要比本地存储好?
弗拉迪斯拉夫·图拉克

1
@TurakVladyslav你是对的,这里确实没有什么区别,只是sessionStorage如果要测试开发,使用可以更容易地设置断点。对于“更好”,没有真正的论据,实际上,这只是出于个人喜好而会产生谨慎的一面。要注意的主要事情是,sessionStoragelocalStorage都是HTML5 Webstorage API的实现。
DrewT'9


3

这是基于上述DrewT回答的扩展解决方案,如果localStorage不可用,则使用cookie。它使用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

正如其他答案中已经解释的那样,在“私人浏览”模式下, Safari 尝试使用保存数据时,总是会抛出此异常localStorage.setItem()

为了解决这个问题,我写了一个伪造的localStorage来模仿localStorage,包括方法和事件。

假本地存储:https : //gist.github.com/engelfrost/fd707819658f72b42f55

这可能不是解决该问题的好方法。对于我的方案而言,这是一个很好的解决方案,其中的替代方案是对现有应用程序的重大重写。


它到底能解决什么?它没有任何持久性,那有什么意义呢?
Esben Skov Pedersen

1
在私人浏览模式下,它可以“修复” Safari。(我的答案不清楚,感谢您指出。我将编辑我的答案)。无论如何,在私有浏览模式下都不应该保留任何内容,因此,不保留不是此处的相关问题。对我来说,这是为了使用户即使不使用Safari的“私人浏览”模式,也可以运行现有的应用程序而无需进行大量重写。
约瑟夫·恩格尔弗斯特

2

更新(2016-11-01)

我正在使用下面提到的AmplifyJS解决此问题。但是,对于私有浏览中的Safari,它回退到基于内存的存储。就我而言,这是不合适的,因为这意味着即使用户仍处于私人浏览状态,存储也会在刷新时清除。

另外,我注意到许多用户始终在iOS Safari上以“私人”模式浏览。因此,对于Safari来说,更好的后备方法是使用Cookie(如果有)。默认情况下,即使在私人浏览中,cookie仍然可以访问。当然,退出私有浏览时将清除它们,但刷新时不会清除它们。

我找到了本地存储后备库。从文档中:

目的

使用诸如“私人浏览”之类的浏览器设置,即使在较新的浏览器中,依靠有效的window.localStorage也已成为一个问题。即使它可能存在,在尝试使用setItem或getItem时也会抛出异常。该模块将运行适当的检查,以查看可能使用的浏览器存储机制,然后将其公开。它使用与localStorage相同的API,因此在大多数情况下,它应该可以作为替代产品。

当心陷阱:

  • CookieStorage有存储限制。小心点
  • 在页面加载之间,MemoryStorage将不会持久。这或多或少是一个防止页面崩溃的权宜之计,但对于不进行完整页面加载的网站可能就足够了。

TL; DR:

使用local-storage-fallback(带有.getItem(prop)和的统一API .setItem(prop, val)):

检查并为浏览器使用适当的存储适配器(localStorage,sessionStorage,Cookie,内存)

原始答案

要添加先前的答案,一种可能的解决方法是更改​​存储方法。有一些库可以帮助,例如AmplifyJSPersistJS。这两个库都允许通过多个后端进行持久的客户端存储。

对于AmplifyJS

本地存储

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

sessionStorage

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

全球存储

  • Firefox 2+

用户数据

  • IE 5-7
  • userData也存在于较新版本的IE中,但是由于IE 9的实现存在古怪之处,如果支持localStorage,则不会注册userData。

记忆

  • 如果没有其他可用的存储类型,则将内存存储作为备用。

对于PersistentJS

  • flash:Flash 8持久存储。
  • gears:基于Google Gears的持久性存储。
  • localstorage:HTML5草案存储。
  • globalstorage:HTML5草案存储(旧规范)。
  • 即:Internet Explorer用户数据行为。
  • cookie:基于cookie的持久性存储。

它们提供了一个抽象层,因此您不必担心选择存储类型。请记住,根据存储类型的不同,可能会有一些限制(例如大小限制)。现在,我正在使用AmplifyJS,但仍然需要在iOS 7 / Safari / etc上进行更多测试。看看它是否真的解决了问题。


编辑John:我知道您和Jonathan Alzetta可能是同一个帐户,并且您只是在尝试改善答案,但是如果是这样,您应该以Jonathan Alzetta的身份登录并编辑此答案,这样就不会通过了审核队列。如果需要,请恢复您的帐户。
DavidS


0

这个问题和答案帮助我解决了在Parse中注册新用户的特定问题。

因为signUp(attrs,options)函数使用本地存储来持久化会话,所以如果用户处于私有浏览模式,则它将引发“ QuotaExceededError:DOM异常22:试图向存储中添加超出配额的内容。” 永远不会调用异常和成功/错误功能。

在我的情况下,由于从未调用过错误函数,因此最初似乎是引发提交时的单击事件或成功注册后定义的重定向的问题。

包括对用户的警告已解决了该问题。

解析Javascript SDK参考 https://parse.com/docs/js/api/classes/Parse.User.html#methods_signUp

使用用户名(或电子邮件)和密码注册新用户。这将在服务器上创建一个新的Parse.User,并将会话保留在localStorage中,以便您可以使用{@link #current}访问该用户。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.