Хранение данных в браузере
Хранение в браузере - cookies, storage и IndexedDB
Страница может сохранять данные на клиенте — настройки темы, черновик формы, кэш справочника, идентификатор сессии. У каждого API свой объём, срок жизни и модель безопасности. Выбор неправильного хранилища ведёт к утечкам, переполнению квоты или потере данных при закрытии вкладки.
Краткие упоминания есть в основах JavaScript; здесь — сравнение и практика.
Распределение данных по хранилищам
В одном приложении обычно сосуществуют несколько типов данных — тема UI, сессия, черновик формы, офлайн-кэш. Один механизм "на всё" (часто localStorage) смешивает секреты, настройки и большие объёмы. Разделяйте по назначению: вкладка → sessionStorage; сессия с сервером → HttpOnly cookie; настройки → localStorage; крупные структуры → IndexedDB (см. сводную таблицу ниже).
Сводная таблица
| Механизм | Объём (ориентир) | Срок жизни | Отправка на сервер | Тип данных |
|---|---|---|---|---|
| Cookie | ~4 КБ на cookie | задаётся Expires / Max-Age | да, с каждым запросом к домену | строка |
| sessionStorage | ~5 МБ на origin | до закрытия вкладки | нет | строка (ключ–значение) |
| localStorage | ~5 МБ на origin | пока пользователь не очистит | нет | строка |
| IndexedDB | сотни МБ+ (браузер решает) | постоянно, пока не удалят | нет | объекты, бинарные данные |
Все четыре привязаны к origin (схема + хост + порт). Поддомены — отдельные origin, если не настроено иначе.
sessionStorage и localStorage
API одинаковый; разница только в времени жизни.
localStorage.setItem('theme', 'dark');
const theme = localStorage.getItem('theme'); // 'dark'
localStorage.removeItem('theme');
localStorage.clear(); // всё для этого origin
sessionStorage.setItem('wizard-step', '2');
Разбор:
setItem(key, value)сохраняет строковое значение по ключу в выбранном хранилище.getItem('theme')возвращает строку илиnull, если ключ отсутствует.removeItem('theme')удаляет один конкретный ключ без влияния на остальные данные.clear()очищает всё хранилище текущего origin, поэтому его используют осторожно.sessionStorageизолирован рамками текущей вкладки, в отличие отlocalStorage.
Хранятся только строки. Объекты — через JSON:
const draft = { title: 'Черновик', body: '…' };
localStorage.setItem('post-draft', JSON.stringify(draft));
const saved = JSON.parse(localStorage.getItem('post-draft') ?? 'null');
Разбор:
JSON.stringify(draft)сериализует объект в строку, пригодную для хранения в Web Storage.JSON.parse(...)восстанавливает структуру объекта при чтении из storage.- Оператор
?? 'null'подставляет безопасное значение, если ключа нет, и предотвращает ошибку парсинга. - Такой цикл "serialize/deserialize" нужен для любых сложных структур — массивов, вложенных объектов, настроек.
- В продакшене полезно добавлять версию схемы, чтобы корректно мигрировать старые сохранённые данные.
Когда использовать
- localStorage — тема, язык UI, флаги "подсказку уже закрывали", несекретные настройки.
- sessionStorage — многошаговая форма в одной вкладке, временное состояние мастера.
Ограничения
- Синхронный API — на больших данных блокирует главный поток.
- Нет доступа из Web Worker напрямую (только через main thread или обёртки).
- При приватном режиме данные могут не сохраняться между сессиями.
Cookies
Устанавливаются заголовком Set-Cookie с сервера или из JS (с ограничениями):
document.cookie = 'prefs=compact; path=/; max-age=31536000; SameSite=Lax';
Разбор:
document.cookie = ...создаёт или обновляет cookie в форматеимя=значение; атрибуты.path=/делает cookie доступной по всему сайту, а не только в текущем разделе URL.max-age=31536000задаёт срок жизни в секундах (примерно один год).SameSite=Laxснижает риск CSRF при кросс-сайтовых переходах, сохраняя типовой UX.- JavaScript не может выставить
HttpOnly, поэтому чувствительные сессионные cookie лучше ставить с сервера.
Чтение — разбор строки document.cookie (неудобно); для сложной логики чаще работают через сервер или библиотеку.
| Атрибут | Назначение |
|---|---|
HttpOnly | недоступно из JS — защита от кражи через XSS |
Secure | только по HTTPS |
SameSite | ограничение при кросс-сайтовых запросах |
Path / Domain | область действия |
Сессия и JWT: токены аутентификации с флагом HttpOnly не кладут в localStorage — при XSS их прочитают. Предпочтительно cookie с HttpOnly + Secure или память вкладки + refresh по короткоживущей cookie.
Logout и очистка данных сайта
Для сценария logout сервер может вернуть заголовок Clear-Site-Data, чтобы сразу удалить клиентские данные текущего origin.
Clear-Site-Data: "cache", "cookies", "storage"
Разбор:
-
Заголовок
Clear-Site-Dataотправляет сервер и управляет очисткой клиентских данных для текущего origin. -
Токен
"cache"удаляет HTTP-кэш,"cookies"очищает cookie,"storage"сбрасывает web storage и IndexedDB. -
Это системный механизм браузера, который удобен для logout и аварийной очистки состояния клиента.
-
Заголовок применяют вместе с серверной инвалидиацией сессии, чтобы убрать и токены, и локальные артефакты.
-
"cache"очищает HTTP-кэш; -
"cookies"удаляет cookie; -
"storage"очищаетlocalStorage,sessionStorage, IndexedDB и Cache API; -
"*"очищает всё сразу.
Практика — на logout сначала инвалидируйте сессию на сервере, затем отдайте Clear-Site-Data, и после этого делайте редирект на страницу входа.
Подробный разбор синтаксиса и ограничений — в справочнике по HTTP.
IndexedDB
Клиентская база объектов с индексами и транзакциями. Подходит для офлайн-кэша, больших списков, файловых blob.
Код ITЗагрузка примера кода…
Разбор:
indexedDB.open('AppCache', 1)открывает базу и использует номер версии для миграций схемы.- Обработчик
onupgradeneededвыполняется при создании базы или повышении версии и подходит дляcreateObjectStore. createObjectStore('articles', { keyPath: 'id' })задаёт хранилище объектов с первичным ключомid.onsuccessвозвращает объектIDBDatabase, аonerrorпередаёт причину ошибки открытия.- В
saveArticleтранзакцияreadwriteоткрывает запись,put(article)создаёт или обновляет объект. - Завершение через
tx.oncompleteгарантирует, что изменения действительно зафиксированы.
API событийное и многословное; в проектах часто оборачивают в idb или хранят в Service Worker + Cache API для статики.
Когда IndexedDB
- офлайн-first приложение (PWA);
- тысячи записей с поиском по полю;
- кэш ответов API с версионированием схемы (
versionвopen).
Не нужен для пары строк настроек — хватит localStorage.
Безопасность
| Риск | Мера |
|---|---|
XSS читает localStorage | не хранить секреты; Content-Security-Policy, санитизация вывода |
| CSRF с cookie | SameSite, токены в заголовке, проверка origin на сервере |
| Утечка между вкладками | sessionStorage изолирует вкладку; cookie — общие для браузера |
| Потеря данных | критичное — на сервере; клиент — только кэш |
Выбор за 30 секунд
- Нужно отправлять серверу каждый запрос? → cookie (часто с сервера).
- Настройки UI, некритично, навсегда? → localStorage.
- Только пока открыта вкладка? → sessionStorage.
- Много записей, офлайн, индексы? → IndexedDB.
Практический шаблон — что где хранить в одном приложении
Пример для типичного кабинета пользователя:
| Данные | Рекомендуемое хранилище | Почему |
|---|---|---|
| Тема интерфейса, плотность таблиц | localStorage | быстрый доступ, мало данных |
| Текущий шаг мастера "Оформление заказа" | sessionStorage | изоляция по вкладкам |
| Сессионный идентификатор | HttpOnly cookie | защита от чтения через XSS |
| Каталог товаров для офлайн-поиска | IndexedDB | много записей, индексы и транзакции |
Эта схема хорошо стыкуется с валидацией форм, чтением файлов и работой с Service Worker, когда проект переходит к офлайн-режиму.
Антипаттерны
- Секреты и refresh-токены складываются в
localStorage, что повышает риск утечки при XSS. - Большие JSON-блоки записываются в
localStorageна каждом символе ввода и вызывают "фризы". - Cookie используется как универсальное хранилище интерфейсных флагов, из-за чего растёт размер каждого HTTP-запроса.
- Нет политики очистки старых данных и миграции схемы IndexedDB между версиями приложения.
Краткий итог
Четыре уровня хранения дополняют друг друга. Для веб-приложений по умолчанию — настройки — localStorage, сессия авторизации — HttpOnly cookie, офлайн-данные — IndexedDB. Всё чувствительное дублируйте проверкой на сервере.
Базовый разбор HTTP и HTTPS находится в отдельной статье — HTTP как основа веб-интеграций.