webroad.online
  1. 1Веб
  2. 2HTML
  3. 3CSS
  4. 4JavaScript
  5. 5TypeScript
  6. 6Git
  7. 7Инструменты
  8. 8React
  9. 9Стейт-менеджмент
  10. 10Next.js
  11. 11Формы
  12. 12Данные и бэкенд
  13. 13SEO
  14. 14Tailwind CSS
  15. 15Анимации
  16. 16Тестирование
  17. 17Архитектура
Веб · Урок 6 из 7

Cookie, localStorage, sessionStorage

5 мест, где браузер хранит данные, и когда что использовать.

Обновлено

Зачем нужно хранилище в браузере

HTTP не хранит состояние: сервер не знает, что запрос 2 пришёл от того же человека, что и запрос 1. А страница при перезагрузке начинает с нуля. Чтобы что-то «запомнить» — вход, корзину, настройки, наполовину заполненную форму, — нужно место, где данные сохраняются.

Браузер даёт 5 таких мест, у каждого своя задача.

Сравнение видов хранилища

Cookie localStorage sessionStorage IndexedDB Cache Storage
Что хранит небольшой текст текст (ключ → строка) текст (ключ → строка) объекты, файлы, blob целые HTTP-ответы
Объём ~4 КБ на cookie ~5 МБ на origin ~5 МБ на origin сотни МБ+ сотни МБ+
Автоматически уходит на сервер да, с каждым запросом нет нет нет нет
Сколько живёт до Max-Age / Expires всегда пока жива вкладка всегда всегда
Видно в всех вкладках всех вкладках только текущей вкладке всех вкладках всех вкладках
API заголовок / document.cookie синхронный синхронный асинхронный асинхронный
Читается из JS да, если не HttpOnly да да да да
Для чего сессия, авторизация, анонимный id настройки UI, черновики состояние мастера / формы во вкладке офлайн-данные, большой кэш PWA, офлайн (service worker)

Все они изолированы по origin: a.com не может прочитать то, что сохранил b.com.

Cookie — это небольшой текст, который устанавливает сервер, а браузер автоматически отправляет обратно с каждым запросом к тому же сайту. Поэтому это единственный способ, которым сервер может вас узнать.

Set-Cookie: session=abc123; Max-Age=2592000; Path=/; HttpOnly; Secure; SameSite=Lax
Атрибут Что делает
Max-Age / Expires сколько живёт; без них — сессионная cookie (исчезает при закрытии браузера)
HttpOnly JS не может её прочитать → защита от XSS
Secure отправляется только по HTTPS
SameSite=Lax не отправляется с POST-запросами с других сайтов → защита от CSRF
SameSite=Strict вообще не отправляется с других сайтов
SameSite=None отправляется всегда (нужен Secure) — для межсайтовых интеграций
Path / Domain для каких URL отправляется

Это приложение ставит cookie vid (httpOnly) — так оно узнаёт ваш прогресс на сервере без регистрации.

В Next cookie читают через cookies() из next/headers, а устанавливают в Server Actions, Route Handlers или proxy.ts.

localStorage

Хранилище ключ → строка, постоянное, общее для всех вкладок одного сайта.

localStorage.setItem('theme', 'dark')
localStorage.getItem('theme')                 // 'dark'
localStorage.removeItem('theme')

localStorage.setItem('cart', JSON.stringify(cart))   // объекты → JSON
const cart = JSON.parse(localStorage.getItem('cart') ?? '[]')
  • Только строки — объекты проходят через JSON.stringify / JSON.parse.
  • Синхронный API: блокирует поток; не сохраняйте мегабайты на каждое нажатие клавиши.
  • Когда одна вкладка меняет localStorage, остальные вкладки получают событие storage — так синхронизируют тему между вкладками.

sessionStorage

Тот же API, что и у localStorage, но данные живут только пока жива вкладка:

Ситуация sessionStorage
перезагрузка страницы (F5) сохраняется
переход на другой URL в той же вкладке и обратно сохраняется
открыть сайт в новой вкладке пусто — у каждой вкладки своё хранилище
«Дублировать вкладку» копируется в новую вкладку, дальше живёт отдельно
закрыть вкладку удаляется
sessionStorage.setItem('checkout-step', '2')
sessionStorage.getItem('checkout-step')       // '2' — только в этой вкладке

Когда он лучше localStorage: мастер оформления заказа или длинная форма, открытые в двух вкладках, — каждая вкладка хранит свой прогресс и не мешает другой.

IndexedDB

База данных в браузере: таблицы (object stores), индексы, транзакции, целые объекты (не только строки), файлы. API асинхронный (не блокирует страницу), но многословный — на практике используют небольшую обёртку:

import { get, set } from 'idb-keyval'
await set('drafts', [{ id: 1, text: '...' }])   // объекты напрямую, без JSON
const drafts = await get('drafts')

Для: офлайн-приложений, кэша больших данных, файлов пользователя до загрузки.

Cache Storage

Хранит целые пары запрос → ответ. Его используют service workers, чтобы сайт работал офлайн (PWA). В обычных приложениях вы редко трогаете его напрямую.

Правила безопасности

  • Никогда не храните токены авторизации в localStorage / sessionStorage — любой скрипт на странице (включая внедрённый через XSS) может их прочитать. Сессия живёт в cookie с HttpOnly.
  • Хранилище может выбросить ошибку (приватный режим, переполнение, заблокированные данные сайта) → оборачивайте каждое чтение / запись в try/catch.
  • На сервере его нет: в Next читайте его только в Client Components после монтирования (в useEffect или useSyncExternalStore), иначе будут ошибки гидратации.
  • Пользователь может очистить его в любой момент — это ненадёжное хранилище для важных данных.

Как выбрать

Нужно... Используйте
чтобы сервер знал, кто вы cookie с HttpOnly
чтобы настройка пережила перезапуск localStorage
отдельное состояние для каждой вкладки, исчезающее при закрытии sessionStorage
большие данные, объекты, офлайн IndexedDB
состояние, которым можно поделиться ссылкой (фильтры, страница) URL, а не хранилище
важные данные на любом устройстве сервер (база данных)

Коротко

  • Cookie — единственное, что уходит на сервер автоматически; для сессий HttpOnly; Secure; SameSite=Lax.
  • localStorage — постоянно, все вкладки; sessionStorage — на вкладку, до закрытия; оба только строки и синхронные.
  • IndexedDB — для больших и офлайн-данных; никаких секретов в хранилище; всегда try/catch.

Официальные источники

Упражнения

Была ли страница полезной?

Один клик — без регистрации.