Перейти к основному содержимому

Хранение данных в браузере

Разработчику Архитектору

Хранение в браузере - 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 с cookieSameSite, токены в заголовке, проверка origin на сервере
Утечка между вкладкамиsessionStorage изолирует вкладку; cookie — общие для браузера
Потеря данныхкритичное — на сервере; клиент — только кэш

Выбор за 30 секунд

  1. Нужно отправлять серверу каждый запрос? → cookie (часто с сервера).
  2. Настройки UI, некритично, навсегда? → localStorage.
  3. Только пока открыта вкладка? → sessionStorage.
  4. Много записей, офлайн, индексы? → IndexedDB.

Практический шаблон — что где хранить в одном приложении

Пример для типичного кабинета пользователя:

ДанныеРекомендуемое хранилищеПочему
Тема интерфейса, плотность таблицlocalStorageбыстрый доступ, мало данных
Текущий шаг мастера "Оформление заказа"sessionStorageизоляция по вкладкам
Сессионный идентификаторHttpOnly cookieзащита от чтения через XSS
Каталог товаров для офлайн-поискаIndexedDBмного записей, индексы и транзакции

Эта схема хорошо стыкуется с валидацией форм, чтением файлов и работой с Service Worker, когда проект переходит к офлайн-режиму.


Антипаттерны

  • Секреты и refresh-токены складываются в localStorage, что повышает риск утечки при XSS.
  • Большие JSON-блоки записываются в localStorage на каждом символе ввода и вызывают "фризы".
  • Cookie используется как универсальное хранилище интерфейсных флагов, из-за чего растёт размер каждого HTTP-запроса.
  • Нет политики очистки старых данных и миграции схемы IndexedDB между версиями приложения.

Краткий итог

Четыре уровня хранения дополняют друг друга. Для веб-приложений по умолчанию — настройкиlocalStorage, сессия авторизацииHttpOnly cookie, офлайн-данные — IndexedDB. Всё чувствительное дублируйте проверкой на сервере.


Основа по протоколу

Базовый разбор HTTP и HTTPS находится в отдельной статье — HTTP как основа веб-интеграций.