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

时间:2014-01-16 10:35:53

标签: javascript iphone html5 local-storage

在iOS 7上使用iPhone上的LocalStorage会引发此错误。我一直在寻找一个解决方案,但考虑到我甚至没有私下浏览,没有任何相关性。

我不明白为什么在iOS 7中默认禁用localStorage,但它似乎是?我也在其他网站上测试过,但没有运气。我甚至尝试使用这个网站进行测试:http://arty.name/localstorage.html,但它似乎并没有因为一些奇怪的原因而保存任何东西。

有没有人有同样的问题,只有他们有运气修复它?我应该切换我的存储方法吗?

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

9 个答案:

答案 0 :(得分:360)

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

一种解决方案是警告用户该应用需要非私人模式才能工作。

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

答案 1 :(得分:103)

正如其他答案中所提到的,当调用localStorage.setItem(或sessionStorage.setItem)时,您将始终在iOS和OS X上的Safari私有浏览器模式中获得QuotaExceededError。

一种解决方案是在使用setItem的每个实例中执行try / catch或Modernizr check

但是,如果你想要一个简单地全局停止抛出此错误的垫片,为了防止其他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.');
    }
}

答案 2 :(得分: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')
}

答案 3 :(得分:5)

I happened to run with the same issue in iOS 7(某些设备没有模拟器)。

看起来iOS 7中的Safari具有较低的存储配额,显然是通过长历史记录来实现的。

我想最好的做法是捕捉异常。

Modernizr项目有一个简单的补丁,你应该尝试类似的东西:https://github.com/Modernizr/Modernizr/blob/master/feature-detects/storage/localstorage.js

答案 4 :(得分:3)

以下是基于DrewT上述答案的扩展解决方案,如果localStorage不可用,则使用cookie。它使用Mozilla的docCookies library

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

答案 5 :(得分:2)

正如其他答案中所述,在私密浏览模式下在尝试使用localStorage.setItem()保存数据时,Safari会总是抛出此异常。

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

假冒localStorage:https://gist.github.com/engelfrost/fd707819658f72b42f55

这可能不是解决问题的一般方法。这对我的场景来说是一个很好的解决方案,其替代方案是对现有应用程序进行重大重写。

答案 6 :(得分:2)

更新(2016-11-01)

我正在使用下面提到的AmplifyJS来解决这个问题。然而,对于私人浏览中的Safari,它正在回归到基于内存的存储。在我的情况下,这是不合适的,因为这意味着即使用户仍处于隐私浏览状态,刷新时也会清除存储空间。

此外,我注意到许多用户总是在iOS Safari上以私密模式浏览。出于这个原因,Safari的更好的后备是使用cookie(如果可用)。默认情况下,即使在私密浏览中,cookie仍可访问。当然,它们在退出私人浏览时被清除,但它们在刷新时不会被清除。

我找到了local-storage-fallback库。来自文档:

  

目的

     

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

谨防陷阱:

  
      
  • CookieStorage具有存储限制。这里要小心。
  •   
  • MemoryStorage不会在页面加载之间保持不变。这或多或少是阻止页面崩溃的障碍,但对于不执行整页加载的网站来说可能就足够了。
  •   

TL; DR:

使用local-storage-fallback(统一API与.getItem(prop).setItem(prop, val)):

  

检查并使用适当的浏览器存储适配器(localStorage,sessionStorage,cookies,memory)

原始答案

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

对于AmplifyJS

  

localStorage的

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

globalStorage的

     
      
  • Firefox 2 +
  •   
     

的UserData

     
      
  • IE 5 - 7
  •   
  • userData也存在于较新版本的IE中,但由于IE 9实现中的怪癖,如果localStorage,我们不会注册userData   得到支持。
  •   
     

存储器

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

对于PersistentJS

  
      
  • flash:Flash 8持久存储。
  •   
  • 齿轮:基于Google Gears的持久存储。
  •   
  • localstorage:HTML5草稿存储。
  •   
  • globalstorage:HTML5草稿存储(旧规范)。
  •   
  • ie:Internet Explorer用户数据行为。
  •   
  • cookie:基于Cookie的持久存储。
  •   

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

答案 7 :(得分:1)

2017年4月,一个补丁被合并到Safari中,因此它与其他浏览器保持一致。这是在Safari 11中发布的。

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

答案 8 :(得分:0)

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

因为signUp(attrs,options)函数使用本地存储来持久化会话,如果用户处于隐私浏览模式,它会抛出“QuotaExceededError:DOM Exception 22:尝试向存储中添加超出配额。”异常,永远不会调用成功/错误函数。

在我的情况下,因为永远不会调用错误函数,所以最初似乎是在提交时触发click事件或在注册成功时定义的重定向问题。

为用户添加警告解决了问题。

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

  

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