Safari 的 html5 localStorage 错误:“QUOTA_EXCEEDED_ERR:DOM 异常 22:尝试向存储添加超出配额的内容。”

IT技术 javascript html local-storage
2021-02-10 01:43:45

我的 web 应用程序在 ios safari 隐私浏览中有 javascript 错误:

JavaScript:错误

不明确的

QUOTA_EXCEEDED_ERR:DOM 异常 22:尝试向存储中添加内容...

我的代码:

localStorage.setItem('test',1)
6个回答

显然这是设计使然。当 Safari(OS X 或 iOS)处于隐私浏览模式时,它看起来好像localStorage可用,但尝试调用setItem会引发异常。

store.js line 73
"QUOTA_EXCEEDED_ERR: DOM Exception 22: An attempt was made to add something to storage that exceeded the quota."

发生的情况是 window 对象仍然暴露localStorage在全局命名空间中,但是当您调用 时setItem,会抛出此异常。任何调用都将removeItem被忽略。

我相信最简单的修复(虽然我还没有测试过这个跨浏览器)是改变函数isLocalStorageNameSupported()来测试你也可以设置一些值。

https://github.com/marcuswestin/store.js/issues/42

function isLocalStorageNameSupported() 
{
    var testKey = 'test', storage = window.sessionStorage;
    try 
    {
        storage.setItem(testKey, '1');
        storage.removeItem(testKey);
        return localStorageName in win && win[localStorageName];
    } 
    catch (error) 
    {
        return false;
    }
}
这不一定是由于隐身模式...虽然我猜 OP 不想存储几兆字节的数据;)
2021-03-18 01:43:45
查看此要点,其中显示了 Paul Irish 检测本地存储的简要历史。
2021-03-18 01:43:45
验证问题不仅与私人窗口有关,而且与普通的 safari 窗口有关。
2021-03-19 01:43:45
类似于 Paul Irish 的例子,我建议return localStorageName in win && win[localStorageName];改为return true. 然后你有一个函数,它根据 localStorage 的可用性安全地返回 true 或 false。例如:if (isLocalStorageNameSupported()) { /* You can use localStorage.setItem */ } else { /* you can't use localStorage.setItem */ }
2021-03-22 01:43:45
那么,如果 localStorage 在 Safari 中不起作用,那么将所有内容存储在 cookie 中是下一个最佳选择吗?
2021-04-06 01:43:45

上面链接上发布的修复程序对我不起作用。这做到了:

function isLocalStorageNameSupported() {
  var testKey = 'test', storage = window.localStorage;
  try {
    storage.setItem(testKey, '1');
    storage.removeItem(testKey);
    return true;
  } catch (error) {
    return false;
  }
}

源自http://m.cg/post/13095478393/detect-private-browsing-mode-in-mobile-safari-on-ios5

@DawsonToth 不,那是因为我调用了该函数isLocalStorageNameSupported并正在检查window.sessionStorage. 相同的最终结果,但有点令人困惑。对答案进行了编辑以澄清。
2021-03-19 01:43:45
@Novocaine 我的评论指出他们在存在的函数中使用 sessionStorage 来检查 localStorage 支持。是的,它可能仍然有效,但是,正如所写的,函数名称对实际测试的内容具有误导性。我选择评论,而不是编辑,因为我觉得我错过了一些东西,希望向这些人学习。不幸的是,他们没有回复或进行更正,所以我们在这里。
2021-03-21 01:43:45
@Yetti 我猜你想知道的是为什么window.localStoragevs 简单localStorage如果是这样,那就不是打字错误——这是一种检查是否localStorage实际定义的安全方法,因为它也将挂window在 JavaScript中的对象之外。如果您只是检查if (localStorage) {},则会抛出异常,但if (window.localStorage) {行为符合预期。我知道已经有几年了,但你在回答几年后问了,所以......为什么不呢。:)
2021-03-29 01:43:45
@Yetti 如果您注意到一个错字,为什么不在编辑或评论中更正它?据我所知window.sessionStorage是正确的。它当然适用于我的代码。请实际指出您似乎知道的问题修复方法。
2021-04-08 01:43:45
您(和@KingKongFrog)使用 window.sessionStorage 来检测您是否可以写入 localStorage 或者我们是否处于奇怪的复制粘贴错字循环中的任何特殊原因?
2021-04-12 01:43:45

正如其他答案中提到的,当localStorage.setItem(或sessionStorage.setItem) 被调用时,在 iOS 和 OS X 上的 Safari Private Browser Mode 中,您总是会得到 QuotaExceededError

一种解决方案是在每个 using 实例中进行try/catch 或Modernizr 检查setItem

但是,如果您想要一个简单地全局停止抛出此错误的 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.');
    }
}

在我的上下文中,刚刚开发了一个类抽象。当我的应用程序启动时,我通过调用getStorage()检查 localStorage 是否正常工作此函数还返回:

  • 如果 localStorage 正在工作,则为 localStorage
  • 或自定义类LocalStorageAlternative 的实现

在我的代码中,我从不直接调用 localStorage。我调用cusSto全局变量,我已经通过调用getStorage() 进行了初始化

这样,它适用于隐私浏览或特定的 Safari 版本

function getStorage() {

    var storageImpl;

     try { 
        localStorage.setItem("storage", ""); 
        localStorage.removeItem("storage");
        storageImpl = localStorage;
     }
     catch (err) { 
         storageImpl = new LocalStorageAlternative();
     }

    return storageImpl;

}

function LocalStorageAlternative() {

    var structureLocalStorage = {};

    this.setItem = function (key, value) {
        structureLocalStorage[key] = value;
    }

    this.getItem = function (key) {
        if(typeof structureLocalStorage[key] != 'undefined' ) {
            return structureLocalStorage[key];
        }
        else {
            return null;
        }
    }

    this.removeItem = function (key) {
        structureLocalStorage[key] = undefined;
    }
}

cusSto = getStorage();
哈。我做了同样的事情(独立)。仍然使用 localStorage 变量(至少在 Safari 中,您不能覆盖 localStorage 变量(它是“只读”),但您可以重新分配 setItem/removeItem/getItem)。
2021-03-13 01:43:45
@user1149244 Memorystorage 是页面本地的。它模拟 Web Storage API,因此可以用作 localStorage 和 sessionStorage 不可用时的后备。然而,数据只会保留在页面存储器中(因此得名)。如果您需要跨页面保留数据,cookie 可能会帮助您。但它可以存储的数据量非常有限。除此之外没有太多可以做的。
2021-03-15 01:43:45
@StijndeWitt,我如何访问其他页面中的存储值?例如,我在 helper.php 中有这个 var store = MemoryStorage('my-app'); store.setItem('myString', 'Hello MemoryStorage!'); 我想访问lecture.php 中myString 的值。我尝试在页面中启动 memorystorage 但它仍然显示一个空对象。
2021-03-27 01:43:45
谢谢皮埃尔,你的回答激励了我。我最终将它全部打包在一个名为memorystorage的漂亮module中当然是开源。对于遇到相同问题的其他人,请查看它可能对您有所帮助。
2021-04-07 01:43:45
@user1149244这不是应该将值存储在浏览器中吗?不,不能。有 3 种方法可以在客户端存储从一个页面刷新到另一个页面的内容:cookie、sessionStorage/localStorage 和 IndexedDB。最后两个比较新。sessionStorage 和 localStorage 受到广泛支持,因此您基本上可以在任何地方使用它。除了在隐私浏览模式下,这就是这个问题的所在。程序因为没有存储而崩溃。memorystorage 只是提供了一个在页面上始终有效的后备,但它实际上无法保存数据。这是一个存根。但没有错误。
2021-04-11 01:43:45

Safari 11 似乎改变了行为,现在本地存储在私人浏览器窗口中工作。万岁!

我们曾经在 Safari 隐私浏览中失败的网络应用程序现在可以完美运行。它在 Chrome 的隐私浏览模式下始终运行良好,该模式始终允许写入本地存储。

这记录在 Apple 的Safari Technology Preview 发行说明WebKit 发行说明中,适用于 2017 年 5 月发布的第 29 版。

具体来说:

  • 修复了在隐私浏览模式或 WebDriver 会话中保存到 localStorage 时的 QuotaExceededError - r215315