在带有 iOS 7 的 iPhone 上使用 LocalStorage 会引发此错误。我一直在寻找解决方案,但考虑到我什至没有私下浏览,没有什么是相关的。
我不明白为什么在 iOS 7 中默认会禁用 localStorage,但似乎是这样?我也在其他网站上测试过,但没有运气。我什至尝试使用以下网站对其进行测试:http://arty.name/localstorage.html,但出于某种奇怪的原因,它似乎根本没有保存任何东西。
有没有人遇到过同样的问题,只是他们有运气解决它?我应该切换我的存储方式吗?
我尝试通过仅存储几行信息来对其进行硬调试,但无济于事。我使用标准的 localStorage.setItem()
函数来保存。
当 Safari 处于隐私模式浏览时,可能会发生这种情况。在隐私浏览中,本地存储根本不可用。
一种解决方案是警告用户应用程序需要非私有模式才能工作。
更新:这已在 Safari 11 中修复,因此该行为现在与其他浏览器保持一致。
正如其他答案中提到的,当调用 localStorage.setItem
(或 sessionStorage.setItem
)时,您总是会在 iOS 和 OS X 上的 Safari 私人浏览器模式下获得 QuotaExceededError。
一种解决方案是在使用 setItem
的每个实例中执行 try/catch 或 Modernizr check。
但是,如果您想要一个简单地全局阻止此错误抛出的 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.');
}
}
我使用这个返回 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')
}
isLocalStorageNameSupported
的方法中使用 window.sessionStorage
而不是 window.localStorage
?
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)
sessionStorage
可以更容易地设置断点。对于哪个“更好”没有真正的论据,这实际上只是个人偏好,在谨慎方面会犯错。主要需要注意的是 sessionStorage
和 localStorage
都是 HTML5 webstorage API 的实现。
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
这是基于上述 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' );
...
正如其他答案中已经解释的那样,当处于隐私浏览模式时 Safari 将总是在尝试使用 localStorage.setItem()
保存数据时抛出此异常。
为了解决这个问题,我编写了一个模仿 localStorage 的假 localStorage,包括方法和事件。
假本地存储:https://gist.github.com/engelfrost/fd707819658f72b42f55
这可能不是解决问题的一个好的通用解决方案。对于我的场景来说,这是一个很好的解决方案,在这种情况下,替代方案是对已经存在的应用程序进行重大重写。
更新 (2016-11-01)
我正在使用下面提到的 AmplifyJS 来解决这个问题。但是,对于私人浏览中的 Safari,它正在回退到基于内存的存储。在我的情况下,这是不合适的,因为这意味着存储在刷新时被清除,即使用户仍在隐私浏览中。
另外,我注意到一些用户总是在 iOS Safari 上以隐私模式浏览。出于这个原因,Safari 的一个更好的后备方案是使用 cookie(如果可用)。默认情况下,即使在私密浏览中仍可访问 cookie。当然,退出隐私浏览时会被清除,但刷新时不会被清除。
我找到了 local-storage-fallback 库。从文档中:
目的 对于像“私人浏览”这样的浏览器设置,即使在较新的浏览器中,依赖工作的 window.localStorage 也已成为一个问题。即使它可能存在,它也会在尝试使用 setItem 或 getItem 时抛出异常。该模块将运行适当的检查以查看可能可用的浏览器存储机制,然后将其公开。它使用与 localStorage 相同的 API,因此在大多数情况下它应该可以作为替代品。
当心陷阱:
CookieStorage 有存储限制。这里要小心。 MemoryStorage 不会在页面加载之间持续存在。这或多或少是防止页面崩溃的权宜之计,但对于不进行整页加载的网站来说可能就足够了。
TL;博士:
使用 local-storage-fallback(具有 .getItem(prop)
和 .setItem(prop, val)
的统一 API):
检查并使用适合浏览器的存储适配器(localStorage、sessionStorage、cookies、内存)
原始答案
要添加以前的答案,一种可能的解决方法是更改存储方法。有一些库(例如 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 实现中的怪癖,如果支持 localStorage,我们不会注册 userData。内存 如果没有其他存储类型可用,则提供内存存储作为后备。
对于 PersistentJS
flash:Flash 8 持久存储。 gears:基于 Google Gears 的持久存储。 localstorage:HTML5 草稿存储。 globalstorage:HTML5 草稿存储(旧规范)。即:Internet Explorer 用户数据行为。 cookie:基于 cookie 的持久存储。
它们提供了一个抽象层,因此您不必担心选择存储类型。请记住,根据存储类型,可能会有一些限制(例如大小限制)。现在,我正在使用 AmplifyJS,但我仍然需要在 iOS 7/Safari/etc 上进行更多测试。看看它是否真的解决了问题。
2017 年 4 月,一个补丁被合并到 Safari 中,因此它与其他浏览器保持一致。这是随 Safari 11 一起发布的。
https://bugs.webkit.org/show_bug.cgi?id=157010
这个问题和答案帮助我解决了在 Parse 中注册新用户的特定问题。
因为 signUp( attrs, options ) 函数使用本地存储来保持会话,如果用户处于隐私浏览模式,它会抛出“QuotaExceededError: DOM Exception 22: 尝试向存储中添加超出配额的内容”。异常和成功/错误函数永远不会被调用。
就我而言,由于从未调用过错误函数,因此最初似乎是在提交时触发点击事件或在注册成功时定义的重定向的问题。
包括对用户的警告解决了该问题。
解析 Javascript SDK 参考 https://parse.com/docs/js/api/classes/Parse.User.html#methods_signUp
使用用户名(或电子邮件)和密码注册新用户。这将在服务器上创建一个新的 Parse.User,并将会话保存在 localStorage 中,以便您可以使用 {@link #current} 访问用户。
if( typeof Storage != 'undefined' ) { ... }
) 是否存在。结果发现Storage
即使在它不可用时仍然被定义。从现在开始每当我使用 LocalStorage 时都使用 try/catch。