私のwebappのios safariプライベートブラウジングでjavascriptエラーがあります。
JavaScript:エラー
未定義
QUOTA_EXCEEDED_ERR:DOM例外22:ストレージに何かを追加しようとしました...
私のコード:
localStorage.setItem('test',1)
私のwebappのios safariプライベートブラウジングでjavascriptエラーがあります。
JavaScript:エラー
未定義
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
です。最終結果は同じですが、少し混乱しました。回答が明確になるように編集されました。
他の回答で述べたように、iOSとOS Xの両方でSafariプライベートブラウザーモードで常にQuotaExceededErrorが発生しますlocalStorage.setItem
(またはsessionStorage.setItem
)が呼び出されるとます。
1つの解決策は、使用の各インスタンスでtry / catchまたはModernizrチェックを実行することですsetItem
。
ただし、このエラーのスローをグローバルに停止するシムが必要な場合は、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を直接呼び出すことはありません。私はcusStoグローバル変数を呼び出し、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のプライベートブラウジングで失敗していた私たちのWebアプリが問題なく動作するようになりました。それは常にローカルストレージへの書き込みを許可していたChromeのプライベートブラウジングモードで常に正常に動作しました。
これは、2017年5月にリリースされたリリース29のAppleのSafari Technology Previewリリースノート、およびWebKitリリースノートに記載されています。
具体的には:
他の人の答えを拡張するために、ここに新しい変数を公開/追加しないコンパクトなソリューションがあります。すべてのベースをカバーしているわけではありませんが、単一ページアプリを機能させたままにしたいほとんどのユーザーに適しています(リロード後のデータの永続性はありません)。
(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 = {};
};
}
})();
Ionicフレームワーク(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');
}
};
}
]);
このリポジトリを作成sessionStorage
しlocalStorage
て、サポートされていない、または無効になっているブラウザに機能を提供しました。
サポートされているブラウザ
使い方
ストレージタイプで機能を検出します。
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
れているwindow.sessionStorage
場合、またはSPAのメモリ内ストレージ、非SPAのセッション機能を備えたCookieストレージを作成する場合に設定します。
これはメモリストレージの代替としてAngular2 +サービスバージョンです。ピエールルルーの回答に基づいて、コンポーネントに注入するだけです。
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をサポートしているかどうかを確認しています。そうでない場合、ストレージエンジンはCookieになります。しかし、マイナス面はCookieのストレージメモリが非常に小さいことです:(
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);
}
}
このスニペットを次のように使用し、たとえばcookieを使用するようにフォールバックします。
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
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();
}
localStorageが存在し、使用できるかどうかを確認します。負の場合は、偽のローカルストレージを作成し、元のlocalStorageの代わりに使用します。さらに情報が必要な場合はお知らせください。