Javascript Safari出现html5本地存储错误:";配额“超出”错误:DOM异常22:试图向超出配额的存储中添加内容;
我的webapp在ios safari私人浏览中出现javascript错误: JavaScript:错误 未定义 配额\u已超过\u错误:DOM异常22:试图向存储中添加某些内容 我的代码:Javascript Safari出现html5本地存储错误:";配额“超出”错误:DOM异常22:试图向超出配额的存储中添加内容;,javascript,html,local-storage,Javascript,Html,Local Storage,我的webapp在ios safari私人浏览中出现javascript错误: JavaScript:错误 未定义 配额\u已超过\u错误:DOM异常22:试图向存储中添加某些内容 我的代码: localStorage.setItem('test',1) 显然这是故意的。当Safari(OS X或iOS)处于私人浏览模式时,似乎localStorage可用,但尝试调用setItem会引发异常 store.js line 73 "QUOTA_EXCEEDED_ERR: DOM Exception
localStorage.setItem('test',1)
显然这是故意的。当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."
发生的情况是,窗口对象仍然在全局命名空间中公开localStorage
,但是当您调用setItem
时,会引发此异常。对removietem
的任何调用都将被忽略
我相信最简单的修复方法(尽管我还没有测试这个跨浏览器)是修改函数isLocalStorageNameSupported()
,以测试您还可以设置一些值
上面链接上发布的补丁对我不起作用。这确实:
function isLocalStorageNameSupported() {
var testKey = 'test', storage = window.localStorage;
try {
storage.setItem(testKey, '1');
storage.removeItem(testKey);
return true;
} catch (error) {
return false;
}
}
源于我的上下文中的,刚刚开发了一个类抽象。 启动应用程序时,我通过调用getStorage()检查本地存储是否正常工作。此函数还返回:
- 如果localStorage正在工作,则选择localStorage
- 或自定义类的实现LocalStorageAlternative
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();
我在使用离子骨架(Angular+Cordova)时也遇到了同样的问题。我知道这不能解决问题,但这是基于上述答案的Angular应用程序代码。在iOS版本的Safari上,您将有一个本地存储的临时解决方案 代码如下:
angular.module('myApp.factories', [])
.factory('$fakeStorage', [
function(){
function FakeStorage() {};
FakeStorage.prototype.setItem = function (key, value) {
this[key] = value;
};
FakeStorage.prototype.getItem = function (key) {
return typeof this[key] == 'undefined' ? null : this[key];
}
FakeStorage.prototype.removeItem = function (key) {
this[key] = undefined;
};
FakeStorage.prototype.clear = function(){
for (var key in this) {
if( this.hasOwnProperty(key) )
{
this.removeItem(key);
}
}
};
FakeStorage.prototype.key = function(index){
return Object.keys(this)[index];
};
return new FakeStorage();
}
])
.factory('$localstorage', [
'$window', '$fakeStorage',
function($window, $fakeStorage) {
function isStorageSupported(storageName)
{
var testKey = 'test',
storage = $window[storageName];
try
{
storage.setItem(testKey, '1');
storage.removeItem(testKey);
return true;
}
catch (error)
{
return false;
}
}
var storage = isStorageSupported('localStorage') ? $window.localStorage : $fakeStorage;
return {
set: function(key, value) {
storage.setItem(key, value);
},
get: function(key, defaultValue) {
return storage.getItem(key) || defaultValue;
},
setObject: function(key, value) {
storage.setItem(key, JSON.stringify(value));
},
getObject: function(key) {
return JSON.parse(storage.getItem(key) || '{}');
},
remove: function(key){
storage.removeItem(key);
},
clear: function() {
storage.clear();
},
key: function(index){
storage.key(index);
}
}
}
]);
资料来源:
享受你的编码 如其他答案中所述,当调用
localStorage.setItem
(或sessionStorage.setItem
)时,在iOS和OS X上的Safari专用浏览器模式下,您总是会收到QuoteExceedeError
一种解决方案是在使用setItem
的每个实例中执行try/catch或
但是,如果您希望使用一个垫片来全局停止抛出此错误,以防止其余JavaScript中断,您可以使用以下方法:
这里有一个AngularJS的解决方案,它使用 这将导致在首次注入服务时立即设置
isLocalStorageAvailable
,避免每次需要访问本地存储时不必要地运行检查
angular.module('app.auth.services', []).service('Session', ['$log', '$window',
function Session($log, $window) {
var isLocalStorageAvailable = (function() {
try {
$window.localStorage.world = 'hello';
delete $window.localStorage.world;
return true;
} catch (ex) {
return false;
}
})();
this.store = function(key, value) {
if (isLocalStorageAvailable) {
$window.localStorage[key] = value;
} else {
$log.warn('Local Storage is not available');
}
};
}
]);
为了扩展其他人的答案,这里有一个紧凑的解决方案,它不公开/添加任何新变量。它并没有涵盖所有的基础,但它应该适合那些只希望单页应用程序保持功能的大多数人(尽管重新加载后没有数据持久性)
(函数(){
试一试{
setItem(“存储测试”、“测试”);
localStorage.removeItem(“存储测试”);
}捕获(exc){
var tmp_storage={};
var p='\uuuuu unique\uuuu';//为所有键添加前缀以避免匹配内置项
Storage.prototype.setItem=函数(k,v){
tmp_存储[p+k]=v;
};
Storage.prototype.getItem=函数(k){
返回tmp_存储器[p+k]==未定义?空:tmp_存储器[p+k];
};
Storage.prototype.removietem=函数(k){
删除tmp_存储器[p+k];
};
Storage.prototype.clear=函数(){
tmp_存储={};
};
}
})();
以下脚本解决了我的问题:
// Fake localStorage implementation.
// Mimics localStorage, including events.
// It will work just like localStorage, except for the persistant storage part.
var fakeLocalStorage = function() {
var fakeLocalStorage = {};
var storage;
// If Storage exists we modify it to write to our fakeLocalStorage object instead.
// If Storage does not exist we create an empty object.
if (window.Storage && window.localStorage) {
storage = window.Storage.prototype;
} else {
// We don't bother implementing a fake Storage object
window.localStorage = {};
storage = window.localStorage;
}
// For older IE
if (!window.location.origin) {
window.location.origin = window.location.protocol + "//" + window.location.hostname + (window.location.port ? ':' + window.location.port: '');
}
var dispatchStorageEvent = function(key, newValue) {
var oldValue = (key == null) ? null : storage.getItem(key); // `==` to match both null and undefined
var url = location.href.substr(location.origin.length);
var storageEvent = document.createEvent('StorageEvent'); // For IE, http://stackoverflow.com/a/25514935/1214183
storageEvent.initStorageEvent('storage', false, false, key, oldValue, newValue, url, null);
window.dispatchEvent(storageEvent);
};
storage.key = function(i) {
var key = Object.keys(fakeLocalStorage)[i];
return typeof key === 'string' ? key : null;
};
storage.getItem = function(key) {
return typeof fakeLocalStorage[key] === 'string' ? fakeLocalStorage[key] : null;
};
storage.setItem = function(key, value) {
dispatchStorageEvent(key, value);
fakeLocalStorage[key] = String(value);
};
storage.removeItem = function(key) {
dispatchStorageEvent(key, null);
delete fakeLocalStorage[key];
};
storage.clear = function() {
dispatchStorageEvent(null, null);
fakeLocalStorage = {};
};
};
// Example of how to use it
if (typeof window.localStorage === 'object') {
// Safari will throw a fit if we try to use localStorage.setItem in private browsing mode.
try {
localStorage.setItem('localStorageTest', 1);
localStorage.removeItem('localStorageTest');
} catch (e) {
fakeLocalStorage();
}
} else {
// Use fake localStorage for any browser that does not support it.
fakeLocalStorage();
}
它检查本地存储是否存在并可以使用,如果不存在,它会创建一个假的本地存储并使用它,而不是原始的本地存储。
如果您需要更多信息,请告诉我。如果不支持,请不要使用它,要检查支持情况,请调用此函数
使用支持检查在Es6中共享完全读写本地存储示例
这将确保在所有浏览器上正确设置和检索密钥
我创建它只是为了为不受支持或禁用的浏览器提供sessionStorage
和localStorage
功能
支持的浏览器
- IE5+
- Chrome所有版本
- Mozilla所有版本
- Yandex所有版本
function(type) {
var testKey = '__isSupported',
storage = window[type];
try {
storage.setItem(testKey, '1');
storage.removeItem(testKey);
return true;
} catch (error) {
return false;
}
};
如果支持或创建cookie存储,则将StorageService.localStorage
设置为window.localStorage
。
将
StorageService.sessionStorage
设置为窗口。sessionStorage
如果受支持或为SPA创建内存中存储,则为非SPA创建具有sesion功能的cookie存储。Safari 11似乎改变了行为,现在本地存储在专用浏览器窗口中工作。万岁
我们曾经在Safari私人浏览中失败的web应用现在可以完美地工作。在Chrome的私有浏览模式下,它总是工作得很好,该模式始终允许写入本地存储
这一点在2017年5月苹果发布的第29版中有记录
具体而言:
- 修复了在私人浏览模式或WebDriver会话中保存到本地存储时出现的QuotaExceedeError-
import { Injectable } from '@angular/core';
// Alternative to localstorage, memory
// storage for certain browsers in private mode
export class LocalStorageAlternative {
private structureLocalStorage = {};
setItem(key: string, value: string): void {
this.structureLocalStorage[key] = value;
}
getItem(key: string): string {
if (typeof this.structureLocalStorage[key] !== 'undefined' ) {
return this.structureLocalStorage[key];
}
return null;
}
removeItem(key: string): void {
this.structureLocalStorage[key] = undefined;
}
}
@Injectable()
export class StorageService {
private storageEngine;
constructor() {
try {
localStorage.setItem('storage_test', '');
localStorage.removeItem('storage_test');
this.storageEngine = localStorage;
} catch (err) {
this.storageEngine = new LocalStorageAlternative();
}
}
setItem(key: string, value: string): void {
this.storageEngine.setItem(key, value);
}
getItem(key: string): string {
return this.storageEngine.getItem(key);
}
removeItem(key: string): void {
this.storageEngine.removeItem(key);
}
}
我已经为这个问题创建了一个补丁。我只是检查浏览器是否支持本地存储或会话存储。如果不是,则存储引擎将是Cookie。但不利的一面是Cookie的存储内存非常小:(
功能存储引擎(引擎){
这个发动机|
const LOCAL_STORAGE_KEY = 'tds_app_localdata';
const isSupported = () => {
try {
localStorage.setItem('supported', '1');
localStorage.removeItem('supported');
return true;
} catch (error) {
return false;
}
};
const writeToLocalStorage =
components =>
(isSupported ?
localStorage.setItem(LOCAL_STORAGE_KEY, JSON.stringify(components))
: components);
const isEmpty = component => (!component || Object.keys(component).length === 0);
const readFromLocalStorage =
() => (isSupported ? JSON.parse(localStorage.getItem(LOCAL_STORAGE_KEY)) || {} : null);
function(type) {
var testKey = '__isSupported',
storage = window[type];
try {
storage.setItem(testKey, '1');
storage.removeItem(testKey);
return true;
} catch (error) {
return false;
}
};
var mod = 'test';
try {
sessionStorage.setItem(mod, mod);
sessionStorage.removeItem(mod);
return true;
} catch (e) {
return false;
}
import { Injectable } from '@angular/core';
// Alternative to localstorage, memory
// storage for certain browsers in private mode
export class LocalStorageAlternative {
private structureLocalStorage = {};
setItem(key: string, value: string): void {
this.structureLocalStorage[key] = value;
}
getItem(key: string): string {
if (typeof this.structureLocalStorage[key] !== 'undefined' ) {
return this.structureLocalStorage[key];
}
return null;
}
removeItem(key: string): void {
this.structureLocalStorage[key] = undefined;
}
}
@Injectable()
export class StorageService {
private storageEngine;
constructor() {
try {
localStorage.setItem('storage_test', '');
localStorage.removeItem('storage_test');
this.storageEngine = localStorage;
} catch (err) {
this.storageEngine = new LocalStorageAlternative();
}
}
setItem(key: string, value: string): void {
this.storageEngine.setItem(key, value);
}
getItem(key: string): string {
return this.storageEngine.getItem(key);
}
removeItem(key: string): void {
this.storageEngine.removeItem(key);
}
}
function StorageEngine(engine) {
this.engine = engine || 'localStorage';
if(!this.checkStorageApi(this.engine)) {
// Default engine would be alway cooke
// Safari private browsing issue with localStorage / sessionStorage
this.engine = 'cookie';
}
}
StorageEngine.prototype.checkStorageApi = function(name) {
if(!window[name]) return false;
try {
var tempKey = '__temp_'+Date.now();
window[name].setItem(tempKey, 'hi')
window[name].removeItem(tempKey);
return true;
} catch(e) {
return false;
}
}
StorageEngine.prototype.getItem = function(key) {
if(['sessionStorage', 'localStorage'].includes(this.engine)) {
return window[this.engine].getItem(key);
} else if('cookie') {
var name = key+"=";
var allCookie = decodeURIComponent(document.cookie).split(';');
var cval = [];
for(var i=0; i < allCookie.length; i++) {
if (allCookie[i].trim().indexOf(name) == 0) {
cval = allCookie[i].trim().split("=");
}
}
return (cval.length > 0) ? cval[1] : null;
}
return null;
}
StorageEngine.prototype.setItem = function(key, val, exdays) {
if(['sessionStorage', 'localStorage'].includes(this.engine)) {
window[this.engine].setItem(key, val);
} else if('cookie') {
var d = new Date();
var exdays = exdays || 1;
d.setTime(d.getTime() + (exdays*24*36E5));
var expires = "expires="+ d.toUTCString();
document.cookie = key + "=" + val + ";" + expires + ";path=/";
}
return true;
}
// ------------------------
var StorageEngine = new StorageEngine(); // new StorageEngine('localStorage');
// If your current browser (IOS safary or any) does not support localStorage/sessionStorage, then the default engine will be "cookie"
StorageEngine.setItem('keyName', 'val')
var expireDay = 1; // for cookie only
StorageEngine.setItem('keyName', 'val', expireDay)
StorageEngine.getItem('keyName')
function storageAvailable(type) {
var storage;
try {
storage = window[type];
var x = '__storage_test__';
storage.setItem(x, x);
storage.removeItem(x);
return true;
}
catch(e) {
return e instanceof DOMException && (
// everything except Firefox
e.code === 22 ||
// Firefox
e.code === 1014 ||
// test name field too, because code might not be present
// everything except Firefox
e.name === 'QuotaExceededError' ||
// Firefox
e.name === 'NS_ERROR_DOM_QUOTA_REACHED') &&
// acknowledge QuotaExceededError only if there's something already stored
(storage && storage.length !== 0);
}
}
if (storageAvailable('localStorage')) {
// Yippee! We can use localStorage awesomeness
}
else {
// Too bad, no localStorage for us
document.cookie = key + "=" + encodeURIComponent(value) + expires + "; path=/";
}
import {getSafeStorage} from 'fallbackstorage'
getSafeStorage().setItem('test', '1') // always work