Meine Webapp hat Javascript-Fehler in der privaten Navigation von ios safari:
JavaScript: Fehler
undefined
QUOTA_EXCEEDED_ERR: DOM-Ausnahme 22: Es wurde versucht, etwas zum Speicher hinzuzufügen ...
mein code:
localStorage.setItem('test',1)
Anscheinend ist das beabsichtigt. Wenn sich Safari (OS X oder iOS) im privaten Browsermodus befindet, scheint localStorage
verfügbar zu sein. Der Aufruf von setItem
löst jedoch 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 noch localStorage
im globalen Namespace verfügbar macht. Wenn Sie jedoch setItem
aufrufen, wird diese Ausnahme ausgelöst. Alle Aufrufe von removeItem
werden ignoriert.
Ich glaube, das einfachste Update (obwohl ich diesen Browser 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;
}
}
Das Update, das unter dem obigen Link veröffentlicht wurde, hat für mich 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
Wie in anderen Antworten erwähnt, erhalten Sie den QuotaExceededError im privaten Browser-Modus sowohl unter iOS als auch unter OS X, wenn localStorage.setItem
(oder sessionStorage.setItem
) aufgerufen wird.
Eine Lösung besteht darin, Try/Catch oder Modernizr Check in jeder Instanz von setItem
auszuführen.
Wenn Sie jedoch ein Shim wünschen, das diesen Fehler einfach global verhindert, können Sie Folgendes verwenden, um zu verhindern, dass der Rest Ihres JavaScripts beschädigt wird.
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 ich meine Anwendung gestartet habe, überprüfe ich, ob localStorage funktioniert, indem ich getStorage () aufrufe. Diese Funktion gibt auch Folgendes zurück:
In meinem Code rufe ich localStorage nie direkt an. Ich rufe cusSto global var auf, das ich durch Aufruf von getStorage () initialisiert hatte.
Auf diese Weise funktioniert es beim privaten Surfen oder bei 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();
Um die Antworten anderer zu erweitern, finden Sie hier eine kompakte Lösung, bei der keine neuen Variablen verfügbar gemacht werden. Es deckt nicht alle Grundlagen ab, sollte aber für die meisten Leute geeignet sein, die nur eine einzelne Seiten-App benötigen (obwohl keine Daten persistent sind).
(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 bei der Verwendung von 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 auf der 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 Kodieren!
Hier ist eine Lösung für AngularJS, die ein IIFE verwendet und die Tatsache ausnutzt, dass services Singletons sind.
Dies führt dazu, dass isLocalStorageAvailable
sofort eingestellt wird, wenn der Service zum ersten Mal eingespeist wird, und es unnötig ist, die Prüfung jedes Mal durchzuführen, 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 dieses repo erstellt, um die Funktionen sessionStorage
und localStorage
für nicht unterstützte oder deaktivierte Browser bereitzustellen.
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 StorageService.localStorage
auf window.localStorage
fest, wenn es unterstützt wird oder einen Cookie-Speicher erstellt Legt StorageService.sessionStorage
auf window.sessionStorage
fest, wenn es unterstützt wird, oder erstellt einen Speicher für SPA, Cookie-Speicher mit Sitzungsfunktionen für Nicht-SPA.
Es scheint, dass Safari 11 das Verhalten ändert, und lokaler Speicher funktioniert jetzt in einem privaten Browserfenster. Hurra!
Unsere Web-App, die bisher beim privaten Surfen von Safari fehlgeschlagen ist, funktioniert jetzt einwandfrei. Im privaten Browsing-Modus von Chrome hat es immer gut funktioniert. In diesem Modus wurde immer auf lokalen Speicher geschrieben.
Dies ist in den Versionshinweisen zu Apple Safari Technology Preview - und den WebKit-Versionshinweisen - für Version 29 (Mai 2017) dokumentiert.
Speziell:
freigabe 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.
Hier ist eine Angular2 + -Serviceversion für eine alternative Speicherkapazität, 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);
}
}
var mod = 'test';
try {
sessionStorage.setItem(mod, mod);
sessionStorage.removeItem(mod);
return true;
} catch (e) {
return false;
}