QuotaExceededError: Dom ngoại lệ 22: Một nỗ lực đã được thực hiện để thêm một cái gì đó vào bộ lưu trữ vượt quá hạn ngạch


219

Sử dụng LocalStorage trên iPhone với iOS 7 sẽ gây ra lỗi này. Tôi đã tìm kiếm một giải pháp, nhưng xem xét tôi thậm chí không duyệt web riêng tư, không có gì có liên quan.

Tôi không hiểu tại sao localStorage sẽ bị tắt theo mặc định trong iOS 7, nhưng có vẻ như vậy? Tôi cũng đã thử nghiệm trên các trang web khác, nhưng không có may mắn. Tôi thậm chí đã thử kiểm tra nó bằng trang web này: http://arty.name/localst Storage.html , nhưng có vẻ như nó không tiết kiệm bất cứ điều gì vì một lý do kỳ lạ.

Có ai có cùng một vấn đề, chỉ có họ đã may mắn sửa nó? Tôi có nên chuyển đổi phương thức lưu trữ của tôi?

Tôi đã cố gắng sửa lỗi nó bằng cách chỉ lưu trữ một vài dòng thông tin, nhưng không có kết quả. Tôi đã sử dụng localStorage.setItem()chức năng tiêu chuẩn để lưu.


2
Nó thường có nghĩa là bạn đã cố lưu trữ một cái gì đó với kích thước vượt quá dung lượng lưu trữ có sẵn. Bạn đang sử dụng trình duyệt nào (Safari, Chrome, v.v.)? Bạn có thể chia sẻ thêm một chút về mã bạn đang sử dụng không và nếu có thể thì dữ liệu bạn đang cố lưu trữ.

3
Điều này nên được coi là một lỗi hoặc vấn đề về phía Safari. Điều đó không có nghĩa là bạn không thể sử dụng localStorage ở chế độ ẩn danh ...
Maksim Luzik

Sử dụng một tính năng phát hiện các bài kiểm tra cho vấn đề cụ thể này . Nếu lưu trữ là không có sẵn, hãy xem xét shimming localStorage với memoryStorage . từ chối trách nhiệm: Tôi là tác giả của các gói được liên kết
Stijn de Witt

1
Vào tháng 4 năm 2017, một bản vá đã được sáp nhập vào Safari, vì vậy nó phù hợp với các trình duyệt khác. Sẽ có khả năng hạ cánh trong Safari 11. bug.webkit.org/show_orms.cgi?id=157010
sandstrom

2
Tôi có thể xác nhận điều này đã được sửa trong Safari iOS 11. Đã kiểm tra duyệt web riêng tư + sessionStorage.setItem () sau đó sessionStorage.getItem () thành công trên iPhone6 ​​và iPhone8.
Kevin Gaudin

Câu trả lời:


372

Điều này có thể xảy ra khi Safari ở chế độ duyệt riêng tư. Mặc dù trong trình duyệt riêng tư, bộ nhớ cục bộ hoàn toàn không có sẵn.

Một giải pháp là cảnh báo người dùng rằng ứng dụng cần chế độ không riêng tư để hoạt động.

CẬP NHẬT: Điều này đã được sửa trong Safari 11 , vì vậy hành vi hiện được căn chỉnh với các trình duyệt khác.


4
Bài viết của bạn cực kỳ hữu ích và kịp thời cho tôi hôm nay (chưa đầy 24 giờ sau). Để tham khảo, đây là cách bật / tắt duyệt web riêng tư: imore.com/how-use-private-browsing-ios-7-safari
Nick

12
+1 đã khắc phục sự cố của tôi. Tôi đã kiểm tra sự tồn tại của LocalStorage ( if( typeof Storage != 'undefined' ) { ... }) trước khi thử tải và lưu thông tin nhưng gặp lỗi này. Hóa ra Storagevẫn được xác định ngay cả khi nó không sử dụng được. Sử dụng thử / bắt từ bây giờ bất cứ khi nào tôi sử dụng LocalStorage.
stevendesu

Cảm ơn! Lỗi kỳ lạ bởi safari. Đáng lẽ phải có nhiều thông tin hơn. : D
Sunny R Gupta

2
Một bản sửa lỗi có thể được gửi đến từ Safari Tech Preview 29: "Đã sửa lỗi QuotaExceededError khi lưu vào localStorage ở chế độ duyệt web riêng tư hoặc các phiên WebDriver". Xem developer.apple.com/safari/tĩ-preview/release-notes
Marc Baumbach

1
Điều này cũng có thể xảy ra nếu đạt đến giới hạn lưu trữ có thể dễ dàng thực hiện bằng cách lưu hình ảnh chẳng hạn.
csalmeida

103

Như đã đề cập trong các câu trả lời khác, bạn sẽ luôn nhận được QuotaExceededError trong Chế độ trình duyệt riêng của Safari trên cả iOS và OS X khi localStorage.setItem(hoặc sessionStorage.setItem) được gọi.

Một giải pháp là kiểm tra thử / bắt hoặc Modernizr trong mỗi trường hợp sử dụng setItem.

Tuy nhiên, nếu bạn muốn một shim đơn giản là toàn cầu ngăn chặn lỗi này bị ném, để ngăn phần còn lại của JavaScript bị phá vỡ, bạn có thể sử dụng điều này:

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.');
    }
}

1
Tại sao thêm setItem vào đối tượng Storage nếu bạn không thể sử dụng nó?
Necromancer

4
Quan điểm của đoạn trích của tôi là chỉ cần bỏ qua các lỗi JS bị ném nếu bạn muốn ứng dụng của mình không bị hỏng hoàn toàn trong chế độ riêng tư của Safari.
philfreo

16

Tôi sử dụng chức năng đơn giản này, trả về truehoặc false, để kiểm tra tính khả dụng của localStorage:

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

Bây giờ bạn có thể kiểm tra localStorage.setItem()tính khả dụng trước khi sử dụng nó. Thí dụ:

if ( isLocalStorageNameSupported() ) {
    // can use localStorage.setItem('item','value')
} else {
    // can't use localStorage.setItem('item','value')
}

Tôi đã bỏ lỡ một cái gì đó? Tại sao window.sessionStorageđược sử dụng thay vì window.localStoragecho một phương thức được gọi là isLocalStorageNameSupported?
Ithar

@lthar - xem tài liệu ở đây: w3schools.com/html/html5_webst Storage.asp Quan trọng nhất là phần này: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

@DrewT, nhưng sự khác biệt trong tình huống này là gì nếu bạn xóa khóa kiểm tra của mình? Không quan trọng là tôi sẽ lưu trữ khóa kiểm tra của mình ở đâu nếu tôi sẽ xóa nó. Liệu tôi có sai? Tại sao lưu trữ phiên tốt hơn mà lưu trữ cục bộ?
Vladyslav Turak

1
@TurakVladyslav bạn đúng, thực sự không có gì khác biệt ở đây ngoại trừ việc sử dụng sessionStoragelàm cho nó dễ quản lý hơn để thiết lập các điểm dừng nếu bạn muốn kiểm tra sự phát triển của mình. Không có tranh luận thực sự nào là "tốt hơn" và đó thực sự chỉ là một sở thích cá nhân ở đây có lỗi về mặt thận trọng. Điều chính cần lưu ý là cả hai sessionStoragelocalStorageđều là các triển khai API lưu trữ web HTML5.
DrewT

5

Tôi tình cờ chạy với cùng một vấn đề trong iOS 7 (với một số thiết bị không có trình giả lập).

Có vẻ như Safari trong iOS 7 có dung lượng lưu trữ thấp hơn, điều này rõ ràng đạt được bằng cách có một nhật ký lịch sử lâu dài.

Tôi đoán cách thực hành tốt nhất sẽ là bắt ngoại lệ.

Dự án Modernizr có một bản vá dễ dàng, bạn nên thử một cái gì đó tương tự: https://github.com/Modernizr/Modernizr/blob/master/feature-detects/st Storage / localst Storage.js


3

Đây là một giải pháp mở rộng dựa trên câu trả lời của DrewT ở trên sử dụng cookie nếu localStorage không khả dụng. Nó sử dụng thư viện docCookies của 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;
}

Trong nguồn của bạn, chỉ cần sử dụng:

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

2

Như đã giải thích trong các câu trả lời khác, khi ở chế độ Duyệt web riêng tư, Safari sẽ luôn ném ngoại lệ này khi cố lưu dữ liệu localStorage.setItem().

Để khắc phục điều này, tôi đã viết một localStorage giả bắt chước localStorage, cả phương thức và sự kiện.

Giả mạo địa phương: https://gist.github.com/engelfrost/fd707819658f72b42f55

Đây có lẽ không phải là một giải pháp chung tốt cho vấn đề. Đây là một giải pháp tốt cho kịch bản của tôi, trong đó giải pháp thay thế sẽ được viết lại chính cho một ứng dụng đã có sẵn.


Chính xác thì nó sửa cái gì? Nó không tồn tại bất cứ điều gì, vì vậy vấn đề là gì?
Esben Skov Pedersen

1
Nó "sửa" Safari khi ở chế độ duyệt web riêng tư. (Điều này không rõ ràng trong câu trả lời của tôi, cảm ơn vì đã chỉ ra điều đó. Tôi sẽ chỉnh sửa câu trả lời của mình). Không có gì được cho là tồn tại khi ở chế độ duyệt web riêng tư, vì vậy không tồn tại không phải là vấn đề có liên quan ở đây. Điều này cố định với tôi là cho phép người dùng chạy một ứng dụng đã có sẵn, mà không cần viết lại chính, ngay cả khi ở chế độ Duyệt web riêng tư trong Safari.
Josef Engelfrost

2

Cập nhật (2016-11-01)

Tôi đã sử dụng AmplifyJS được đề cập dưới đây để khắc phục vấn đề này. Tuy nhiên, đối với Safari trong Duyệt web riêng tư, nó đã rơi trở lại vào bộ lưu trữ dựa trên bộ nhớ. Trong trường hợp của tôi, nó không phù hợp vì điều đó có nghĩa là bộ nhớ bị xóa khi làm mới, ngay cả khi người dùng vẫn đang ở chế độ duyệt web riêng tư.

Ngoài ra, tôi đã nhận thấy một số người dùng luôn duyệt ở chế độ Riêng tư trên iOS Safari. Vì lý do đó, một dự phòng tốt hơn cho Safari là sử dụng cookie (nếu có). Theo mặc định, cookie vẫn có thể truy cập ngay cả trong trình duyệt riêng tư. Tất nhiên, chúng sẽ bị xóa khi thoát khỏi trình duyệt riêng tư, nhưng chúng không bị xóa khi làm mới.

Tôi tìm thấy thư viện lưu trữ cục bộ-dự phòng . Từ tài liệu:

Mục đích

Với các cài đặt trình duyệt như "Duyệt web riêng tư", việc dựa vào một cửa sổ đang hoạt động.localStorage đã trở thành một vấn đề, ngay cả trong các trình duyệt mới hơn. Mặc dù nó có thể tồn tại, nó sẽ đưa ra các ngoại lệ khi cố gắng sử dụng setItem hoặc getItem. Mô-đun này sẽ chạy các kiểm tra thích hợp để xem cơ chế lưu trữ trình duyệt nào có thể khả dụng và sau đó hiển thị nó. Nó sử dụng API giống như localStorage, do đó, nó sẽ hoạt động như một sự thay thế thả xuống trong hầu hết các trường hợp.

Cẩn thận với các vấn đề

  • CookieStorage có giới hạn lưu trữ. Hãy cẩn thận ở đây.
  • MemoryStorage sẽ không tồn tại giữa các lần tải trang. Đây ít nhiều là một khoảng trống để ngăn chặn sự cố trang, nhưng có thể đủ cho các trang web không tải toàn bộ trang.

TL; DR:

Sử dụng dự phòng cục bộ-lưu trữ (API hợp nhất với .getItem(prop).setItem(prop, val)):

Kiểm tra và sử dụng bộ điều hợp lưu trữ thích hợp cho trình duyệt (localStorage, sessionStorage, cookies, memory)

Câu trả lời gốc

Để thêm vào các câu trả lời trước đó, một cách giải quyết khác có thể là thay đổi phương thức lưu trữ. Có một vài lời nói dối như AmplifyJSPersistJS có thể giúp đỡ. Cả hai lib đều cho phép lưu trữ phía máy khách liên tục thông qua một số phụ trợ.

Đối với AmplifyJS

lưu trữ cục bộ

  • IE 8+
  • Firefox 3.5+
  • Safari 4+
  • Trình duyệt Chrome
  • Opera 10,5+
  • iPhone 2+
  • Android 2+

phiênStorage

  • IE 8+
  • Firefox 2+
  • Safari 4+
  • Trình duyệt Chrome
  • Opera 10,5+
  • iPhone 2+
  • Android 2+

toàn cầu

  • Firefox 2+

dữ liệu người dùng

  • IE 5 - 7
  • userData cũng tồn tại trong các phiên bản IE mới hơn, nhưng do sự kỳ quặc trong quá trình triển khai của IE 9, chúng tôi không đăng ký userData nếu localStorage được hỗ trợ.

ký ức

  • Cửa hàng trong bộ nhớ được cung cấp dưới dạng dự phòng nếu không có loại lưu trữ nào khác khả dụng.

Dành cho PersistentJS

  • flash: Flash 8 lưu trữ liên tục.
  • bánh răng: lưu trữ liên tục dựa trên Google Gears.
  • localst Storage: Lưu trữ dự thảo HTML5.
  • globalst Storage: Lưu trữ dự thảo HTML5 (thông số cũ).
  • tức là: hành vi người dùng Internet Explorer.
  • cookie: lưu trữ liên tục dựa trên cookie.

Họ cung cấp một lớp trừu tượng để bạn không phải lo lắng về việc chọn loại lưu trữ. Hãy nhớ rằng có thể có một số hạn chế (chẳng hạn như giới hạn kích thước) tùy thuộc vào loại lưu trữ. Ngay bây giờ, tôi đang sử dụng AmplifyJS, nhưng tôi vẫn phải thực hiện thêm một số thử nghiệm trên iOS 7 / Safari / vv. để xem nếu nó thực sự giải quyết vấn đề.


Biên tập viên John: Tôi nhận ra bạn và Jonathan Alzetta có thể là cùng một tài khoản và bạn chỉ đang cố gắng cải thiện câu trả lời của mình, nhưng nếu vậy bạn nên đăng nhập như Jonathan Alzetta và chỉnh sửa câu trả lời này, sau đó nó sẽ không đi qua hàng đánh giá. Khôi phục tài khoản của bạn nếu bạn cần.
DavidS


0

Câu hỏi và câu trả lời này đã giúp tôi giải quyết một vấn đề cụ thể khi đăng ký người dùng mới trong Parse.

Bởi vì chức năng SignUp (attrs, tùy chọn) sử dụng bộ nhớ cục bộ để duy trì phiên, nếu người dùng ở chế độ duyệt riêng tư, nó sẽ ném "QuotaExceededError: DOM Exception 22: Một nỗ lực đã được thực hiện để thêm thứ gì đó vào bộ nhớ vượt quá hạn ngạch." ngoại lệ và các hàm thành công / lỗi không bao giờ được gọi.

Trong trường hợp của tôi, vì chức năng lỗi không bao giờ được gọi, ban đầu dường như là một vấn đề với việc kích hoạt sự kiện nhấp chuột khi gửi hoặc chuyển hướng được xác định khi thành công khi đăng ký.

Bao gồm một cảnh báo cho người dùng đã giải quyết vấn đề.

Tham chiếu SDK Javascript phân tích https://parse.com/docs/js/api/groupes/Pude.User.html#methods_signUp

Đăng ký người dùng mới bằng tên người dùng (hoặc email) và mật khẩu. Điều này sẽ tạo một Parse.User mới trên máy chủ và cũng duy trì phiên trong localStorage để bạn có thể truy cập người dùng bằng cách sử dụng {@link #cản}.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.