Safari의 html5 localStorage 오류 :“QUOTA_EXCEEDED_ERR : DOM 예외 22 : 할당량을 초과 한 스토리지에 무언가를 추가하려고했습니다.”
내 웹 응용 프로그램에 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;
}
}
위 링크에 게시 된 수정 프로그램이 작동하지 않았습니다. 이것은했다 :
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 에서 파생 됨
다른 답변에서 언급했듯이 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.');
}
}
내 맥락에서 방금 클래스 추상화를 개발했습니다. 내 응용 프로그램이 시작되면 getStorage () 를 호출하여 localStorage가 작동하는지 확인합니다 . 이 함수는 다음도 반환합니다.
- localStorage가 작동중인 경우 localStorage
- 또는 사용자 정의 클래스 LocalStorageAlternative 의 구현
내 코드에서는 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의 비공개 브라우징 모드에서 정상적으로 작동하여 항상 로컬 저장소에 쓸 수있었습니다.
이 내용은 2017 년 5 월 릴리스 29 의 Apple Safari Technology Preview 릴리스 노트 및 WebKit 릴리스 노트 에 설명되어 있습니다.
구체적으로 특별히:
- 비공개 브라우징 모드 또는 WebDriver 세션에서 localStorage에 저장할 때 QuotaExceededError 수정 -r215315
다른 사람들의 대답을 확장하기 위해 여기에 새로운 변수를 노출 / 추가하지 않는 소형 솔루션이 있습니다. 모든 기반을 다루지는 않지만 단일 페이지 앱만 작동 상태로 유지하려는 대부분의 사람들에게 적합해야합니다 (다시로드 후 데이터 지속성이 없어도).
(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
지원되지 않는 또는 비활성화 브라우저 있습니다.
지원되는 브라우저
- IE5 +
- 모든 버전의 Chrome
- 모질라 모든 버전
- Yandex 모든 버전
작동 원리
스토리지 유형의 기능을 감지합니다.
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
.
지원되지 않는 경우 사용하지 말고 지원을 확인하려면이 함수를 호출하십시오.
지원 확인을 통해 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);
그러면 모든 브라우저에서 키가 올바르게 설정되고 검색됩니다.
다음은 메모리 스토리지 대안을위한 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);
}
}
var mod = 'test';
try {
sessionStorage.setItem(mod, mod);
sessionStorage.removeItem(mod);
return true;
} catch (e) {
return false;
}
다음 스크립트는 내 문제를 해결했습니다.
// 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();
}
It checks if localStorage exists and can be used and in the negative case, it creates a fake local storage and uses it instead of the original localStorage. Please let me know if you need further information.
'development' 카테고리의 다른 글
일련의 jQuery 연기로 어떻게 작업합니까? (0) | 2020.06.30 |
---|---|
변수가 설정되지 않은 경우 makefile 중단 (0) | 2020.06.30 |
PHP에서 "풀에 메모리를 할당 할 수 없습니다"는 무엇입니까? (0) | 2020.06.30 |
Java에서 HTML 문자 엔티티를 이스케이프 해제하는 방법은 무엇입니까? (0) | 2020.06.30 |
PHP로 RSS / Atom 피드를 파싱하는 가장 좋은 방법 (0) | 2020.06.30 |