QuotaExceededError: Dom exception 22: Upaya telah dilakukan untuk menambahkan sesuatu ke penyimpanan yang melebihi kuota

219

Menggunakan LocalStorage di iPhone dengan iOS 7 melempar kesalahan ini. Saya sudah mencari-cari resolusi, tapi mengingat saya bahkan tidak browsing secara pribadi, tidak ada yang relevan.

Saya tidak mengerti mengapa localStorage akan dinonaktifkan secara default di iOS 7, tetapi sepertinya begitu? Saya telah menguji di situs web lain juga, tetapi tidak berhasil. Saya bahkan mencoba mengujinya menggunakan situs web ini: http://arty.name/localstorage.html , tetapi sepertinya tidak menyimpan apa-apa karena alasan yang aneh.

Adakah yang punya masalah yang sama, hanya saja mereka sudah beruntung memperbaikinya? Haruskah saya beralih metode penyimpanan saya?

Saya mencoba keras debugging dengan hanya menyimpan beberapa baris informasi, tetapi tidak berhasil. Saya menggunakan localStorage.setItem()fungsi standar untuk menyimpan.

Nict
sumber
2
Ini biasanya berarti Anda mencoba menyimpan sesuatu dengan ukuran yang melebihi ruang penyimpanan yang tersedia. Browser apa yang Anda gunakan (Safari, Chrome, dll.)? Bisakah Anda membagikan sedikit lebih banyak kode yang telah Anda gunakan dan jika mungkin data yang Anda coba simpan.
3
Ini harus dianggap sebagai bug atau masalah di sisi Safari. Tidak masuk akal bahwa Anda tidak dapat menggunakan localStorage dalam mode penyamaran ...
Maksim Luzik
Gunakan fitur deteksi yang menguji untuk masalah khusus ini . Jika penyimpanan tidak tersedia, mempertimbangkan shimming localStorage dengan memoryStorage . disclaimer: Saya penulis paket terkait
Stijn de Witt
1
Pada April 2017 tambalan digabungkan ke Safari, sehingga diselaraskan dengan peramban lain. Kemungkinan akan mendarat di Safari 11. bugs.webkit.org/show_bug.cgi?id=157010
sandstrom
2
Saya dapat mengkonfirmasi ini telah diperbaiki di Safari iOS 11. Diuji browsing Pribadi + sessionStorage.setItem () kemudian sessionStorage.getItem () berhasil di iPhone6 ​​dan iPhone8.
Kevin Gaudin

Jawaban:

372

Ini dapat terjadi saat Safari berada dalam mode penelusuran pribadi. Saat dalam penelusuran pribadi, penyimpanan lokal tidak tersedia sama sekali.

Salah satu solusinya adalah untuk memperingatkan pengguna bahwa aplikasi membutuhkan mode non-pribadi untuk bekerja.

UPDATE: Ini telah diperbaiki di Safari 11 , sehingga perilaku sekarang diselaraskan dengan browser lain.

Cristian Dinu
sumber
4
Posting Anda sangat membantu dan tepat waktu untuk saya hari ini (kurang dari 24 jam kemudian). Untuk referensi, berikut cara mengaktifkan / menonaktifkan penelusuran pribadi: imore.com/how-use-private-browsing-ios-7-safari
Nick
12
+1 memperbaiki masalah saya. Saya memeriksa keberadaan LocalStorage ( if( typeof Storage != 'undefined' ) { ... }) sebelum mencoba memuat dan menyimpan informasi tetapi mendapatkan kesalahan ini. Ternyata Storagemasih ditentukan bahkan ketika itu tidak dapat digunakan. Menggunakan try / catch mulai sekarang setiap kali saya menggunakan LocalStorage.
stevendesu
Terima kasih! Kesalahan aneh oleh safari. Seharusnya lebih informatif. : D
Sunny R Gupta
2
Perbaikan mungkin masuk pada Safari Tech Preview 29: "Fixed QuotaExceededError saat menyimpan ke localStorage dalam mode penelusuran pribadi atau sesi WebDriver". Lihat developer.apple.com/safari/technology-preview/release-notes
Marc Baumbach
1
Ini juga dapat terjadi jika batas penyimpanan tercapai yang dapat dengan mudah dilakukan dengan menyimpan gambar misalnya.
csalmeida
103

Seperti disebutkan dalam jawaban lain, Anda akan selalu mendapatkan QuotaExceededError di Safari Private Browser Mode di iOS dan OS X saat localStorage.setItem(atau sessionStorage.setItem) dipanggil.

Salah satu solusinya adalah melakukan pemeriksaan coba / tangkap atau Modernizr di setiap contoh penggunaan setItem.

Namun, jika Anda ingin shim yang secara global menghentikan kesalahan ini, untuk mencegah sisa JavaScript Anda rusak, Anda dapat menggunakan ini:

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.');
    }
}
philfreo
sumber
1
Mengapa menambahkan setItem ke objek Storage jika Anda tidak dapat menggunakannya?
Necromancer
4
Maksud cuplikan saya adalah mengabaikan kesalahan JS agar tidak dilempar jika Anda ingin aplikasi Anda tidak sepenuhnya rusak dalam mode privat Safari.
philfreo
16

Saya menggunakan fungsi sederhana ini, yang mengembalikan trueatau false, untuk menguji ketersediaan localStorage:

isLocalStorageNameSupported = function() {
    var testKey = 'test', storage = window.sessionStorage;
    try {
        storage.setItem(testKey, '1');
        storage.removeItem(testKey);
        return true;
    } catch (error) {
        return false;
    }
}

Sekarang Anda dapat menguji localStorage.setItem()ketersediaan sebelum menggunakannya. Contoh:

if ( isLocalStorageNameSupported() ) {
    // can use localStorage.setItem('item','value')
} else {
    // can't use localStorage.setItem('item','value')
}
DrewT
sumber
Apakah saya melewatkan sesuatu? Mengapa window.sessionStoragedigunakan alih-alih window.localStorageuntuk metode yang disebut isLocalStorageNameSupported?
Ithar
@lthar - lihat dokumentasi di sini: w3schools.com/html/html5_webstorage.asp Yang paling penting bagian ini:HTML local storage provides two objects for storing data on the client: window.localStorage - stores data with no expiration date window.sessionStorage - stores data for one session (data is lost when the browser tab is closed)
DrewT
@Rewt, tapi apa bedanya dalam situasi ini jika Anda menghapus kunci tes Anda? Tidak masalah di mana saya akan menyimpan kunci tes saya jika saya akan menghapusnya. Apakah aku salah? Mengapa penyimpanan sesi lebih baik dari sesi lokal?
Vladyslav Turak
1
@TurakVladyslav Anda benar tidak ada perbedaan di sini kecuali menggunakan sessionStoragemembuatnya lebih mudah untuk mengatur breakpoints jika Anda ingin menguji pengembangan Anda. Tidak ada argumen yang benar yang "lebih baik" dan itu benar-benar hanya preferensi pribadi di sini yang keliru di sisi hati-hati. Hal utama untuk diperhatikan adalah bahwa kedua sessionStoragedan localStoragekeduanya implementasi dari HTML5 WebStorage API.
DrewT
5

Saya kebetulan menjalankan dengan masalah yang sama di iOS 7 (dengan beberapa perangkat tanpa simulator).

Sepertinya Safari di iOS 7 memiliki kuota penyimpanan yang lebih rendah, yang tampaknya dicapai dengan memiliki log riwayat yang panjang.

Saya kira praktik terbaik adalah menangkap pengecualian.

Proyek Modernizr memiliki tambalan mudah, Anda harus mencoba sesuatu yang serupa: https://github.com/Modernizr/Modernizr/blob/master/feature-detects/storage/localstorage.js

defvol
sumber
3

Berikut adalah solusi yang diperluas berdasarkan jawaban DrewT di atas yang menggunakan cookie jika penyimpanan lokal tidak tersedia. Ini menggunakan perpustakaan docCookies Mozilla :

function localStorageGet( pKey ) {
    if( localStorageSupported() ) {
        return localStorage[pKey];
    } else {
        return docCookies.getItem( 'localstorage.'+pKey );
    }
}

function localStorageSet( pKey, pValue ) {
    if( localStorageSupported() ) {
        localStorage[pKey] = pValue;
    } else {
        docCookies.setItem( 'localstorage.'+pKey, pValue );
    }
}

// global to cache value
var gStorageSupported = undefined;
function localStorageSupported() {
    var testKey = 'test', storage = window.sessionStorage;
    if( gStorageSupported === undefined ) {
        try {
            storage.setItem(testKey, '1');
            storage.removeItem(testKey);
            gStorageSupported = true;
        } catch (error) {
            gStorageSupported = false;
        }
    }
    return gStorageSupported;
}

Di sumber Anda, cukup gunakan:

localStorageSet( 'foobar', 'yes' );
...
var foo = localStorageGet( 'foobar' );
...
Stickley
sumber
2

Seperti yang sudah dijelaskan dalam jawaban lain, ketika dalam mode Penjelajahan Pribadi, Safari akan selalu membuang pengecualian ini ketika mencoba menyimpan data localStorage.setItem().

Untuk memperbaikinya saya menulis localStorage palsu yang meniru localStorage, baik metode maupun peristiwa.

LocalStorage palsu: https://gist.github.com/engelfrost/fd707819658f72b42f55

Ini mungkin bukan solusi umum yang baik untuk masalah ini. Ini adalah solusi yang baik untuk skenario saya, di mana alternatifnya akan menjadi menulis ulang besar untuk aplikasi yang sudah ada.

Josef Engelfrost
sumber
Apa tepatnya yang diperbaiki? Itu tidak bertahan apa-apa, jadi apa gunanya?
Esben Skov Pedersen
1
Ini "memperbaiki" Safari ketika dalam mode penelusuran pribadi. (Ini tidak jelas dalam jawaban saya, terima kasih sudah menunjukkannya. Saya akan mengedit jawaban saya). Tidak ada yang seharusnya dipertahankan ketika dalam mode penjelajahan pribadi, jadi tidak bertahan bukanlah masalah yang relevan di sini. Apa yang diperbaiki bagi saya adalah untuk memungkinkan pengguna menjalankan aplikasi yang sudah ada, tanpa menulis ulang utama, bahkan ketika dalam mode Penjelajahan Pribadi di Safari.
Josef Engelfrost
2

Pembaruan (2016-11-01)

Saya menggunakan AmplifyJS yang disebutkan di bawah untuk mengatasi masalah ini. Namun, untuk Safari dalam penjelajahan Pribadi, itu kembali ke penyimpanan berbasis memori. Dalam kasus saya, itu tidak sesuai karena itu berarti penyimpanan dihapus saat refresh, bahkan jika pengguna masih dalam penelusuran pribadi.

Juga, saya perhatikan sejumlah pengguna yang selalu menjelajah dalam mode Privat di iOS Safari. Karena alasan itu, fallback yang lebih baik untuk Safari adalah menggunakan cookie (jika tersedia). Secara default, cookie masih dapat diakses bahkan di penelusuran pribadi. Tentu saja, mereka dihapus ketika keluar dari penjelajahan pribadi, tetapi mereka tidak dihapus saat refresh.

Saya menemukan perpustakaan penyimpanan-fallback lokal . Dari dokumentasi:

Tujuan

Dengan pengaturan peramban seperti "Penjelajahan Pribadi" menjadi masalah untuk mengandalkan jendela yang berfungsi. Penyimpanan lokal, bahkan di peramban yang lebih baru. Meskipun mungkin ada, itu akan membuang pengecualian ketika mencoba menggunakan setItem atau getItem. Modul ini akan menjalankan pemeriksaan yang sesuai untuk melihat mekanisme penyimpanan browser apa yang mungkin tersedia, dan kemudian memaparkannya. Ini menggunakan API yang sama dengan localStorage sehingga harus berfungsi sebagai pengganti drop-in dalam banyak kasus.

Waspadalah terhadap gotcha:

  • CookieStorage memiliki batas penyimpanan. Hati-hati di sini.
  • MemoryStorage tidak akan bertahan di antara pemuatan halaman. Ini lebih atau kurang merupakan celah berhenti untuk mencegah kerusakan halaman, tetapi mungkin cukup untuk situs web yang tidak melakukan pemuatan halaman penuh.

TL; DR:

Gunakan local-storage-fallback (API terpadu dengan .getItem(prop)dan .setItem(prop, val)):

Periksa dan gunakan adaptor penyimpanan yang sesuai untuk browser (Penyimpanan lokal, sesi penyimpanan, cookie, memori)

Jawaban asli

Untuk menambahkan jawaban sebelumnya, satu solusi yang mungkin dilakukan adalah mengubah metode penyimpanan. Ada beberapa librairie seperti AmplifyJS dan PersistJS yang dapat membantu. Kedua lib memungkinkan penyimpanan sisi klien yang persisten melalui beberapa backend.

Untuk AmplifyJS

penyimpanan lokal

  • IE 8+
  • Firefox 3.5+
  • Safari 4+
  • Chrome
  • Opera 10.5+
  • iPhone 2+
  • Android 2+

sessionStorage

  • IE 8+
  • Firefox 2+
  • Safari 4+
  • Chrome
  • Opera 10.5+
  • iPhone 2+
  • Android 2+

globalStorage

  • Firefox 2+

data pengguna

  • IE 5 - 7
  • userData ada di versi IE yang lebih baru juga, tetapi karena kebiasaan dalam implementasi IE 9, kami tidak mendaftarkan userData jika localStorage didukung.

Penyimpanan

  • Toko dalam memori disediakan sebagai cadangan jika tidak ada jenis penyimpanan lain yang tersedia.

Untuk PersistentJS

  • flash: Flash 8 penyimpanan persisten.
  • gears: Penyimpanan persisten berbasis Google Gears.
  • penyimpanan lokal: penyimpanan konsep HTML5.
  • globalstorage: penyimpanan konsep HTML5 (spesifikasi lama).
  • yaitu: perilaku data pengguna Internet Explorer.
  • cookie: penyimpanan persisten berbasis-cookie.

Mereka menawarkan lapisan abstraksi sehingga Anda tidak perlu khawatir memilih jenis penyimpanan. Perlu diingat mungkin ada beberapa batasan (seperti batas ukuran) tergantung pada tipe penyimpanannya. Saat ini, saya menggunakan AmplifyJS, tetapi saya masih harus melakukan beberapa pengujian lagi pada iOS 7 / Safari / dll. untuk melihat apakah itu benar-benar menyelesaikan masalah.

Jonathan Alzetta
sumber
Editor John: Saya menyadari Anda dan Jonathan Alzetta mungkin adalah akun yang sama dan Anda hanya mencoba meningkatkan jawaban Anda, tetapi jika demikian Anda harus benar-benar masuk sebagai Jonathan Alzetta dan mengedit jawaban ini, dan kemudian itu tidak akan melalui antrian ulasan. Pulihkan akun Anda jika perlu.
DavidS
0

Pertanyaan dan jawaban ini membantu saya memecahkan masalah tertentu dengan mendaftar pengguna baru di Parse.

Karena fungsi signUp (attrs, options) menggunakan penyimpanan lokal untuk melanjutkan sesi, jika pengguna berada dalam mode penjelajahan pribadi ia melempar "QuotaExceededError: DOM Pengecualian 22: Upaya dilakukan untuk menambahkan sesuatu ke penyimpanan yang melebihi kuota." fungsi pengecualian dan keberhasilan / kesalahan tidak pernah dipanggil.

Dalam kasus saya, karena fungsi kesalahan yang tidak pernah dipanggil, awalnya tampak sebagai masalah dengan menjalankan peristiwa klik pada ajukan atau pengalihan yang ditentukan pada keberhasilan mendaftar.

Termasuk peringatan untuk pengguna menyelesaikan masalah.

Parse Javascript Referensi SDK https://parse.com/docs/js/api/classes/Parse.User.html#methods_signUp

Mendaftar pengguna baru dengan nama pengguna (atau email) dan kata sandi. Ini akan membuat Parse.User baru di server, dan juga bertahan sesi di localStorage sehingga Anda dapat mengakses pengguna menggunakan {@link #current}.

clayostrom
sumber