Browser Przechowywanie APIs dla Prześlij plików Applications
Leverage IndexedDB, File System Access API, i Cache API dla plik transfer apps. Przechowywanie limits, performance, i browser compatibility.
Przeglądarkowe storage dla aplikacji do transferu plików dzieli się czytelnie na cztery API: IndexedDB dla ustrukturyzowanych metadanych sesji i chunków (transakcyjne, asynchroniczne, typowane), File System Access API do odczytu i zapisu wielogigabajtowych plików bezpośrednio na dysku użytkownika, Cache API dla odpowiedzi HTTP i zasobów app-shell oraz Storage Manager API do zarządzania przydziałem i wskazówkami trwałości. Origin Private File System (OPFS) uzupełnia ten zestaw o sandboxowane, wysokowydajne I/O. Wybór właściwego API ma znaczenie, bo limity wahają się od 1 GB w iOS Safari do „60% wolnego dysku" w desktopowym Chrome — niewłaściwy wybór prędzej czy później powoduje QuotaExceededError na produkcji.
Przyporządkowanie każdego API do właściwego zadania
IndexedDB stosuj do wszystkiego, co przypomina wiersz w bazie: sesje uploadu, indeksy ukończonych chunków, metadane udostępniania, tokeny odwołania. Jest asynchroniczne, transakcyjne, indeksowalne i przeżywa restarty karty.
File System Access API stosuj, gdy musisz zapisywać bajty na dysk bez ładowania całego pliku do RAM — idealne do zapisywania odszyfrowanych pobrań powyżej 500 MB. Chrome, Edge i Opera w pełni go obsługują; Firefox i Safari implementują wyłącznie podzbiór do odczytu przez showOpenFilePicker.
Cache API stosuj dla obiektów HTTP Response — bundle JS, CSS, ikony i ewentualne odpowiedzi API. Jest zoptymalizowane pod przechwytywanie fetch w Service Workers.
OPFS (wyspecjalizowana gałąź Origin-Private File System Access API) stosuj, gdy potrzebujesz szybkiego, sandboxowanego, niewidocznego dla użytkownika storage — na przykład bufora zapisu podczas wielogigabajtowego szyfrowania. Osiąga przepustowość dysku o rząd wielkości wyższą niż IndexedDB przy binarnych blobach.
IndexedDB bez szorstkich krawędzi
Surowe IndexedDB ma notoryjnie niezgrabne API oparte na zdarzeniach. Używaj pakietu idb Jake'a Archibalda (1,5 KB po gzip) lub Dexie.js (20 KB, bogatsze API zapytań):
import { openDB } from 'idb';
const db = await openDB('transfers', 2, {
upgrade(db, oldVersion) {
if (oldVersion < 1) {
const sessions = db.createObjectStore('sessions', { keyPath: 'id' });
sessions.createIndex('by_expiry', 'expiresAt');
}
if (oldVersion < 2) {
db.createObjectStore('chunks', { keyPath: ['sessionId', 'index'] });
}
}
});
await db.put('sessions', { id: 'abc', fileName: 'report.pdf', expiresAt: Date.now() + 86400000 });
Migracje wersji wykonują się w callbacku upgrade. Zawsze zabezpieczaj migracje przez oldVersion, żeby użytkownicy skaczący z v1 do v3 przeszli obydwa kroki.
IndexedDB obsługuje większość kształtów danych, łącznie z Blobami i referencjami do plików, przez strukturalny klon. Oznacza to, że możesz przechować uchwyt File w rekordzie sesji i po przeładowaniu karty odczytać oryginalne bajty — idealne do wznawialnych uploadów.
File System Access API dla dużych pobrań
API pozwala przekazać writable stream do dialogu zapisu przeglądarki:
const handle = await window.showSaveFilePicker({
suggestedName: 'decrypted-archive.zip',
types: [{ description: 'Zip', accept: { 'application/zip': ['.zip'] } }]
});
const writable = await handle.createWritable();
await decryptionStream.pipeTo(writable);
Bajty trafiają prosto na dysk, nigdy nie lądując na stercie JS. To jedyna praktyczna metoda zapisania odszyfrowanego pliku 10 GB w przeglądarce.
Dla Firefox i Safari fallback stanowi StreamSaver.js, który używa Service Workera do syntezy strumieniowej odpowiedzi wyzwalającej UI pobierania. Te same ergonomia, trochę więcej ruchomych części.
Trwałe uchwyty plików pozwalają też aplikacji ponownie otwierać pliki między sesjami. Po jednorazowym przyznaniu uprawnień przez showOpenFilePicker możesz utrwalić FileSystemFileHandle w IndexedDB i później wywołać handle.requestPermission(), żeby odzyskać dostęp bez ponownego pytania o każdy plik.
OPFS jako scratch space
Origin Private File System to sandboxowane storage per-origin zachowujące się jak system plików, ale niewidoczne dla użytkownika:
const root = await navigator.storage.getDirectory();
const fh = await root.getFileHandle('scratch.bin', { create: true });
const access = await fh.createSyncAccessHandle(); // tylko workers
access.write(buffer, { at: offset });
access.flush();
access.close();
createSyncAccessHandle jest dostępny wyłącznie wewnątrz Web Workers (w tym Service Workers). Jest synchroniczny i bardzo szybki — benchmarki pokazują 3–10-krotnie wyższą szybkość niż IndexedDB przy sekwencyjnych zapisach. Używaj go do buforowania kilkuset megabajtów wyjścia szyfrowania przed uploadem lub do przechowywania odszyfrowanej kopii roboczej bez zaśmiecania folderu Pobrane.
Safari 17 dostarczył OPFS z synchronicznymi uchwytami dostępu; Firefox 111 poszedł w jego ślady. Wszystkie trzy główne przeglądarki go obsługują, co czyni go realnym wyborem dla kodu produkcyjnego.
Przydziały storage i jak ich nie przekroczyć
Wszystkie API współdzielą tę samą pulę przydziału per-origin. Przybliżone limity:
- Desktopowy Chrome: 60% wolnego dysku
- Desktopowy Firefox: 50% wolnego dysku, domyślnie ograniczone do 2 GB per origin
- Desktopowy Safari: ostrzeżenie przy 1 GB, rośnie do ~20% dysku za zgodą użytkownika
- iOS Safari: 1 GB per origin, agresywne usuwanie po 7 dniach nieużywania
- Chrome Android: 10% wolnego dysku, usuwanie pod presją
Sprawdź przydział w czasie działania:
const { quota, usage } = await navigator.storage.estimate();
console.log(`Używasz ${(usage/1e9).toFixed(2)} GB z ${(quota/1e9).toFixed(2)} GB`);
Poproś o trwałość dla krytycznych magazynów:
const persisted = await navigator.storage.persist();
Zwraca true, jeśli przeglądarka przyznała trwałe storage — dane nie zostaną usunięte pod presją. Chrome przyznaje to automatycznie stronom z dużym zaangażowaniem użytkownika; Firefox pyta o potwierdzenie.
Cache API dla app shell i trybu offline
Cache API przechowuje pary Request + Response i to właściwy wybór wewnątrz Service Workers:
const cache = await caches.open('shell-v7');
await cache.addAll([
'/', '/app.js', '/app.css', '/icons/192.png'
]);
Pobieranie przy przechwytywaniu:
self.addEventListener('fetch', (e) => {
e.respondWith(caches.match(e.request).then(r => r ?? fetch(e.request)));
});
Nie wkładaj zaszyfrowanych bajtów pliku do Cache API. Obiekt odpowiedzi 2 GB jednorazowo przekracza limit iOS Safari i nie może być pobrany zakresowo po fakcie. Bajty należą do OPFS lub bezpośrednio na dysk przez File System Access.
Obsługa usuwania danych i utraty danych z gracją
Nietrwałe storage może zostać usunięte — musisz się na to przygotować. iOS Safari usuwa po 7 dniach nieużywania, niezależnie od przydziału. Chrome usuwa tylko przy rzeczywistym braku miejsca na dysku. Firefox usuwa origin najrzadziej używane, gdy pula przydziału się zapełnia.
Dwa wzorce obronne:
- Zapisuj każdy stan, którego nie możesz odtworzyć (ID sesji uploadu, częściowe offsety chunków), w formacie przyjaznym dla przeładowania strony, żeby świeże załadowanie karty mogło ponownie pobrać z serwera i kontynuować.
- Dla długożyjącego stanu wywołaj
navigator.storage.persist()i pokaż UI pozwalające użytkownikom potwierdzić, gdy przeglądarka o to prosi.
Traktuj serwer jako źródło prawdy dla wszystkiego, czego nie możesz sobie pozwolić stracić. Przeglądarkowe storage to szybka pamięć podręczna, która może zniknąć z dnia na noc.
Pułapki kompatybilności przeglądarek
Trzy problemy pojawiają się wciąż od nowa:
- Enumeracja
indexedDB.databases()nie jest obsługiwana w Firefox (użytkownicy z włączonym „usuń ciasteczka przy zamknięciu" tracą całą zawartość IndexedDB bez zdarzeń). FileSystemFileHandle.queryPermission()zachowuje się inaczej po przeładowaniu — czasem zwraca'prompt'mimo wcześniej przyznanego uprawnienia. Zawsze wywołujrequestPermission()defensywnie.- Tryb prywatny / incognito daje wszystkim trzem API osobny, mniejszy, tylko-sesyjny przydział. Kod działający w normalnym trybie może natychmiast trafić na
QuotaExceededErrorw oknach prywatnych.
HexaTransfer używa IndexedDB do stanu sesji, OPFS do buforowania szyfrogramu podczas szyfrowania strumieniowego i File System Access API do odszyfrowanych pobrań 10 GB w obsługiwanych przeglądarkach. Wypróbuj na hexatransfer.com — bezpłatnie, bez konta, do 10 GB.
Dobór stosu dla Twojej aplikacji
Dla większości aplikacji transferowych właściwa kombinacja to: wrapper idb nad IndexedDB dla metadanych, synchroniczne uchwyty dostępu OPFS dla scratch space szyfrowania/deszyfrowania, Cache API dla app shell wewnątrz Service Workera, File System Access API dla końcowych pobrań z fallbackiem na StreamSaver oraz wywołanie navigator.storage.persist() podczas onboardingu. Pokrywa to każdą przeglądarce aktualnie dostępną na rynku, mieści się w limitach na mobile i dochodzi do siebie po usunięciu danych. Buduj małe adaptery wokół każdego API — gdy OPFS doczeka się nowej metody albo Safari podniesie swój limit, zmienisz jeden plik.
Wysyłaj duże pliki bezpiecznie z szyfrowaniem end-to-end
Przesyłaj pliki do 10 GB za darmo z szyfrowaniem end-to-end. Bez rejestracji. Twoje pliki są szyfrowane w przeglądarce przed przesłaniem — nikt inny nie może ich odczytać.
Wyślij plik