Meine Webanwendung hat Javascript-Fehler beim privaten Surfen in ios safari:
JavaScript: Fehler
nicht definiert
QUOTA_EXCEEDED_ERR: DOM-Ausnahme 22: Es wurde versucht, dem Speicher etwas hinzuzufügen ...
Mein Code:
localStorage.setItem('test',1)
Meine Webanwendung hat Javascript-Fehler beim privaten Surfen in ios safari:
JavaScript: Fehler
nicht definiert
QUOTA_EXCEEDED_ERR: DOM-Ausnahme 22: Es wurde versucht, dem Speicher etwas hinzuzufügen ...
Mein Code:
localStorage.setItem('test',1)
Antworten:
Anscheinend ist dies beabsichtigt. Wenn sich Safari (OS X oder iOS) im privaten Browsermodus befindet, scheint localStoragees verfügbar zu sein, aber der Versuch, einen Anruf zu tätigen, setItemlöst eine Ausnahme aus.
store.js line 73
"QUOTA_EXCEEDED_ERR: DOM Exception 22: An attempt was made to add something to storage that exceeded the quota."
Was passiert ist, dass das Fensterobjekt immer noch localStorageim globalen Namespace verfügbar gemacht wird, aber wenn Sie aufrufen setItem, wird diese Ausnahme ausgelöst. Alle Anrufe an removeItemwerden ignoriert.
Ich glaube, die einfachste Lösung (obwohl ich diesen Cross-Browser noch nicht getestet habe) wäre, die Funktion isLocalStorageNameSupported()zu ändern, um zu testen, ob Sie auch einen Wert festlegen können.
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;
}
}
return localStorageName in win && win[localStorageName];zu return true. Dann haben Sie eine Funktion, die je nach Verfügbarkeit von localStorage sicher true oder false zurückgibt. Zum Beispiel:if (isLocalStorageNameSupported()) { /* You can use localStorage.setItem */ } else { /* you can't use localStorage.setItem */ }
Das auf dem obigen Link veröffentlichte Update hat bei mir nicht funktioniert. Dies tat:
function isLocalStorageNameSupported() {
var testKey = 'test', storage = window.localStorage;
try {
storage.setItem(testKey, '1');
storage.removeItem(testKey);
return true;
} catch (error) {
return false;
}
}
Abgeleitet von http://m.cg/post/13095478393/detect-private-browsing-mode-in-mobile-safari-on-ios5
window.sessionStorageist richtig. Es funktioniert sicherlich in meinem Code. Bitte weisen Sie tatsächlich auf die Lösung des Problems hin, über das Sie anscheinend Bescheid wissen.
isLocalStorageNameSupportedund überprüft habe window.sessionStorage. Gleiches Endergebnis, aber etwas verwirrend. Die Antwort wurde zur Verdeutlichung bearbeitet.
Wie in anderen Antworten erwähnt, erhalten Sie den QuotaExceededError immer im privaten Safari-Browsermodus unter iOS und OS X, wenn localStorage.setItem(odersessionStorage.setItem ) aufgerufen wird.
Eine Lösung besteht darin , in jedem Verwendungsfall einen Try / Catch- oder Modernizr-Check durchzuführensetItem .
Wenn Sie jedoch einen Shim möchten, der diesen Fehler einfach global verhindert, um zu verhindern, dass der Rest Ihres JavaScript beschädigt wird, können Sie Folgendes verwenden:
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.');
}
}
In meinem Kontext habe ich gerade eine Klassenabstraktion entwickelt. Wenn meine Anwendung gestartet wird, überprüfe ich, ob localStorage funktioniert, indem ich getStorage () aufrufe . Diese Funktion gibt auch zurück:
In meinem Code rufe ich localStorage nie direkt auf. Ich rufe cusSto global var auf, das ich durch Aufrufen von getStorage () initialisiert hatte .
Auf diese Weise funktioniert es mit privatem Surfen oder bestimmten Safari-Versionen
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();
Es scheint, dass Safari 11 das Verhalten ändert und der lokale Speicher jetzt in einem privaten Browserfenster funktioniert. Hurra!
Unsere Web-App, die früher beim privaten Surfen in Safari fehlgeschlagen ist, funktioniert jetzt einwandfrei. Im privaten Browsermodus von Chrome hat es immer gut funktioniert, da immer in den lokalen Speicher geschrieben werden konnte.
Dies ist in den Versionshinweisen zu Safari Technology Preview von Apple - und den Versionshinweisen zu WebKit - für Version 29 dokumentiert , die im Mai 2017 veröffentlicht wurde.
Speziell:
Um die Antworten anderer zu erweitern, finden Sie hier eine kompakte Lösung, die keine neuen Variablen verfügbar macht / hinzufügt. Es deckt nicht alle Basen ab, sollte jedoch für die meisten Benutzer geeignet sein, die nur möchten, dass eine App mit nur einer Seite funktionsfähig bleibt (obwohl nach dem erneuten Laden keine Datenbeständigkeit besteht).
(function(){
try {
localStorage.setItem('_storage_test', 'test');
localStorage.removeItem('_storage_test');
} catch (exc){
var tmp_storage = {};
var p = '__unique__'; // Prefix all keys to avoid matching built-ins
Storage.prototype.setItem = function(k, v){
tmp_storage[p + k] = v;
};
Storage.prototype.getItem = function(k){
return tmp_storage[p + k] === undefined ? null : tmp_storage[p + k];
};
Storage.prototype.removeItem = function(k){
delete tmp_storage[p + k];
};
Storage.prototype.clear = function(){
tmp_storage = {};
};
}
})();
Ich hatte das gleiche Problem mit dem Ionic Framework (Angular + Cordova). Ich weiß, dass dies das Problem nicht löst, aber es ist der Code für Angular Apps, der auf den obigen Antworten basiert. Sie haben eine kurzlebige Lösung für localStorage für die iOS-Version von Safari.
Hier ist der Code:
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);
}
}
}
]);
Quelle: https://gist.github.com/jorgecasar/61fda6590dc2bb17e871
Viel Spaß beim Codieren!
Hier ist eine Lösung für AngularJS, die ein IIFE verwendet und die Tatsache nutzt, dass Dienste Singletons sind .
Dies führt dazu, isLocalStorageAvailabledass die Einstellung sofort beim ersten Injizieren des Dienstes erfolgt und die Prüfung nicht unnötig ausgeführt wird, wenn auf den lokalen Speicher zugegriffen werden muss.
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');
}
};
}
]);
Ich habe gerade diese Repo zur Verfügung zu stellen sessionStorageund localStoragebiete für nicht unterstützten oder fähigen Browser.
Unterstützte Browser
Wie es funktioniert
Es erkennt die Funktion mit dem Speichertyp.
function(type) {
var testKey = '__isSupported',
storage = window[type];
try {
storage.setItem(testKey, '1');
storage.removeItem(testKey);
return true;
} catch (error) {
return false;
}
};
Legt fest StorageService.localStorage, window.localStorageob es unterstützt wird oder ob ein Cookie-Speicher erstellt wird. Legt fest StorageService.sessionStorage, window.sessionStorageob es unterstützt wird oder einen In-Memory-Speicher für SPA erstellt, einen Cookie-Speicher mit Sitzungsfunktionen für Nicht-SPA.
Hier ist eine Angular2 + -Dienstversion für die Speicheralternative, die Sie basierend auf der Antwort von Pierre Le Roux einfach in Ihre Komponenten einfügen können.
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);
}
}
Freigeben in Es6 Lesen und Schreiben von localStorage-Beispiel mit Support-Prüfung
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);
Dadurch wird sichergestellt, dass Ihre Schlüssel in allen Browsern richtig eingestellt und abgerufen werden.
Ich habe einen Patch für das Problem erstellt. Ich überprüfe einfach, ob der Browser localStorage oder sessionStorage unterstützt oder nicht. Wenn nicht, ist die Speicher-Engine Cookie. Aber die negative Seite ist, dass Cookies einen sehr kleinen Speicher haben :(
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')
Die akzeptierte Antwort scheint in mehreren Situationen nicht angemessen zu sein.
Um zu überprüfen, ob die localStorageoder sessionStorageunterstützt werden, verwende ich das folgende Snippet von MDN .
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);
}
}
Verwenden Sie dieses Snippet wie folgt und greifen Sie beispielsweise auf Cookies zurück:
if (storageAvailable('localStorage')) {
// Yippee! We can use localStorage awesomeness
}
else {
// Too bad, no localStorage for us
document.cookie = key + "=" + encodeURIComponent(value) + expires + "; path=/";
}
Ich habe das Fallbackstorage- Paket erstellt, das dieses Snippet verwendet, um die Speicherverfügbarkeit zu überprüfen und auf einen manuell implementierten MemoryStorage zurückzugreifen.
import {getSafeStorage} from 'fallbackstorage'
getSafeStorage().setItem('test', '1') // always work
var mod = 'test';
try {
sessionStorage.setItem(mod, mod);
sessionStorage.removeItem(mod);
return true;
} catch (e) {
return false;
}
Das folgende Skript hat mein Problem gelöst:
// 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();
}
Es prüft, ob localStorage vorhanden ist und verwendet werden kann, und im negativen Fall erstellt es einen gefälschten lokalen Speicher und verwendet ihn anstelle des ursprünglichen localStorage. Bitte lassen Sie mich wissen, wenn Sie weitere Informationen benötigen.