내 웹 응용 프로그램에 iOS 사파리 개인 탐색에서 자바 스크립트 오류가 있습니다.
자바 스크립트 : 오류
찾으시는 주소가 없습니다
QUOTA_EXCEEDED_ERR : DOM 예외 22 : 저장소에 무언가를 추가하려고했습니다 ...
내 코드 :
localStorage.setItem('test',1)
내 웹 응용 프로그램에 iOS 사파리 개인 탐색에서 자바 스크립트 오류가 있습니다.
자바 스크립트 : 오류
찾으시는 주소가 없습니다
QUOTA_EXCEEDED_ERR : DOM 예외 22 : 저장소에 무언가를 추가하려고했습니다 ...
내 코드 :
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
하면이 예외가 발생합니다. 에 대한 모든 호출 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;
}
}
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 */ }
위 링크에 게시 된 수정 프로그램이 작동하지 않았습니다. 이것은했다 :
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 에서 파생 됨
window.sessionStorage
정확합니다. 확실히 내 코드에서 작동합니다. 실제로 알고있는 문제에 대한 해결책 을 지적하십시오 .
isLocalStorageNameSupported
확인 했기 때문 window.sessionStorage
입니다. 같은 결과이지만 약간 혼란 스러웠습니다. 답을 명확하게하기 위해 편집되었습니다.
다른 답변에서 언급했듯이 localStorage.setItem
(또는 sessionStorage.setItem
)가 호출 되면 iOS 및 OS X의 Safari 개인 브라우저 모드에서 항상 QuotaExceededError 가 발생합니다.
한 가지 해결책 은를 사용하는 각 인스턴스에서 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.');
}
}
내 맥락에서 방금 클래스 추상화를 개발했습니다. 내 응용 프로그램이 시작되면 전화를 걸어 localStorage가 작동하는지 확인합니다. getStorage () . 이 함수는 다음도 반환합니다.
내 코드에서는 localStorage를 직접 호출하지 않습니다. 나는 cusSto를 부른다 내가 호출하여 초기화 한 글로벌 VAR 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();
Safari 11이 동작을 변경 한 것으로 보이며 이제 로컬 저장소가 개인 브라우저 창에서 작동합니다. 만세!
Safari 개인 브라우징에서 실패했던 웹 앱은 이제 완벽하게 작동합니다. 항상 Chrome의 비공개 브라우징 모드에서 정상적으로 작동하여 로컬 저장소에 항상 쓸 수있었습니다.
이 내용은 Apple의 Safari Technology Preview 릴리스 정보 및 WebKit 릴리스 정보에 설명되어 있습니다. 2017 년 5 월 릴리스 29 에 설명되어 있습니다.
구체적으로 특별히:
다른 사람들의 대답을 확장하기 위해 여기에 새로운 변수를 노출 / 추가하지 않는 소형 솔루션이 있습니다. 모든 기반을 다루지는 않지만 단일 페이지 앱만 작동 상태로 유지하려는 대부분의 사람들에게 적합해야합니다 (다시로드 후 데이터 지속성이 없어도).
(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 = {};
};
}
})();
이온 프레임 워크 (Angular + Cordova)를 사용하여 동일한 문제가 발생했습니다. 나는 이것이 문제를 해결하지 못한다는 것을 알고 있지만 위의 답변을 기반으로 한 Angular Apps의 코드입니다. iOS 버전의 Safari에서 localStorage를위한 임시 솔루션이 제공됩니다.
코드는 다음과 같습니다.
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);
}
}
}
]);
출처 : https://gist.github.com/jorgecasar/61fda6590dc2bb17e871
코딩을 즐기십시오!
다음은 IIFE를 사용하고 서비스가 싱글 톤 이라는 사실을 활용하는 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');
}
};
}
]);
난 그냥이 만든 REPO 제공을 sessionStorage
하고 localStorage
지원되지 않는 또는 비활성화 브라우저 있습니다.
지원되는 브라우저
작동 원리
스토리지 유형의 기능을 감지합니다.
function(type) {
var testKey = '__isSupported',
storage = window[type];
try {
storage.setItem(testKey, '1');
storage.removeItem(testKey);
return true;
} catch (error) {
return false;
}
};
설정 StorageService.localStorage
에 window.localStorage
이 지원하거나 쿠키의 저장을 생성하는 경우. 지원되는 경우 또는 SPA 이외의 경우 sesion 기능이있는 쿠키 저장소 인 SPA의 메모리 저장소를 작성하는 경우로 설정 StorageService.sessionStorage
합니다 window.sessionStorage
.
다음은 메모리 스토리지 대안을위한 Angular2 + 서비스 버전입니다. Pierre Le Roux의 답변에 따라 구성 요소에 주입 할 수 있습니다.
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);
}
}
지원 확인을 통해 Es6 전체 읽기 및 쓰기 localStorage 예에서 공유
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);
그러면 모든 브라우저에서 키가 올바르게 설정되고 검색됩니다.
이 문제에 대한 패치를 만들었습니다. 브라우저가 localStorage 또는 sessionStorage를 지원하는지 여부를 확인하고 있습니다. 그렇지 않으면 스토리지 엔진은 쿠키입니다. 그러나 부정적인 측면은 쿠키에 매우 작은 저장 메모리가 있다는 것입니다.
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')
몇 가지 상황에서 허용되는 답변이 적합하지 않은 것 같습니다.
localStorage
또는 sessionStorage
지원 여부를 확인하기 위해 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);
}
}
이 스 니펫을 다음과 같이 사용하고 예를 들어 쿠키를 사용하여 대체하십시오.
if (storageAvailable('localStorage')) {
// Yippee! We can use localStorage awesomeness
}
else {
// Too bad, no localStorage for us
document.cookie = key + "=" + encodeURIComponent(value) + expires + "; path=/";
}
이 스 니펫을 사용하여 저장소 가용성을 확인하고 수동으로 구현 된 MemoryStorage로 대체 하는 fallbackstorage 패키지를 만들었습니다 .
import {getSafeStorage} from 'fallbackstorage'
getSafeStorage().setItem('test', '1') // always work
다음 스크립트는 내 문제를 해결했습니다.
// 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();
}
localStorage가 존재하고 사용할 수 있는지 확인하고 부정적인 경우 가짜 로컬 저장소를 만들어 원래 localStorage 대신 사용합니다. 추가 정보가 필요하면 알려주십시오.