在iPhone和iOS 7上使用LocalStorage会抛出这个错误。我一直在寻找一个解决方案,但考虑到我甚至没有私下浏览,没有什么相关的。

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

有没有人遇到过同样的问题,只是他们很幸运地解决了它?我应该改变我的存储方法吗?

我试图通过只存储几行信息来硬调试它,但没有用。我使用标准的localStorage.setItem()函数保存。


我碰巧在iOS 7中遇到了同样的问题(有些设备没有模拟器)。

看起来iOS 7中的Safari有一个更低的存储配额,这显然是通过拥有一个很长的历史日志来达到的。

我认为最好的实践是捕获异常。

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


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

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

更新:这在Safari 11中已经修复,所以行为现在与其他浏览器一致。


正如在其他答案中提到的,当localStorage时,你总是会在iOS和OS X的Safari私有浏览器模式中获得QuotaExceededError。setItem(或sessionStorage.setItem)被调用。

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

然而,如果你想要一个shim,只是全局地阻止这个错误被抛出,以防止你的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.');
    }
}

正如在其他回答中已经解释过的那样,当处于私有浏览模式时,Safari在尝试使用localStorage.setItem()保存数据时总是会抛出这个异常。

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

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

这可能不是解决这个问题的好办法。对于我的场景来说,这是一个很好的解决方案,因为替代方案是对已经存在的应用程序进行重大重写。


我使用这个返回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')
}

更新(2016-11-01)

我使用下面提到的AmplifyJS来解决这个问题。然而,对于Safari Private浏览器来说,它正在退回到基于内存的存储。在我的例子中,这并不合适,因为这意味着刷新时存储将被清除,即使用户仍处于私有浏览状态。

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

我找到了local-storage-fallback库。从文档中可以看到:

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

小心陷阱:

CookieStorage有存储限制。这里要小心。 MemoryStorage将不会在页面加载之间持续存在。这或多或少是一种防止页面崩溃的权宜之计,但对于不进行完整页面加载的网站来说可能已经足够了。

TL; diana:

使用本地存储回退(具有.getItem(prop)和.setItem(prop, val)的统一API):

检查并使用适当的浏览器存储适配器(localStorage、sessionStorage、cookie、内存)

原来的答案

为了补充前面的答案,一种可能的解决方法是改变存储方法。有一些库,如AmplifyJS和PersistJS可以提供帮助。这两个库都允许通过几个后端进行持久的客户端存储。

对于AmplifyJS

localStorage IE 8 + Firefox 3.5 + Safari 4 + 铬 Opera 10.5 + iPhone 2 + 安卓2 + sessionStorage IE 8 + Firefox 2 + Safari 4 + 铬 Opera 10.5 + iPhone 2 + 安卓2 + globalStorage Firefox 2 + 用户数据 Ie 5 - 7 userData也存在于新版本的IE中,但是由于ie9实现中的一些奇怪之处,我们不会在localStorage中注册userData 是支持的。 内存 如果没有其他存储类型可用,则提供内存中存储作为后备。

对于持久化

flash: flash 8持久化存储。 gears:谷歌基于gears的持久存储。 localstorage: HTML5草案存储。 globalstorage: HTML5草案存储(旧规范)。 ie: Internet Explorer用户数据行为。 cookie:基于cookie的持久化存储。

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


下面是一个扩展的解决方案,基于上面DrewT的答案,如果localStorage不可用,则使用cookie。它使用Mozilla的docookie库:

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

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

因为signUp(attrs, options)函数使用本地存储来持久化会话,如果用户处于私有浏览模式,它会抛出“QuotaExceededError: DOM Exception 22: An attempt was made to add something to storage that exceeded the quota.”异常,并且不会调用成功/错误函数。

在我的例子中,因为错误函数从未被调用,它最初似乎是一个问题,在提交上触发单击事件或在注册成功时定义的重定向。

包括一个警告用户解决的问题。

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

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


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

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