DjangoやSpringのようなサーバーサイドフレームワークは、セッション(Session)管理をサーバーで処理し、クッキー(Cookie)を通じてクライアントを識別する方法を主に使用します。サーバーが状態を管理してくれるので便利です。
しかし、React、Vue、AngularのようなSPA(Single Page Application)環境では、クライアント(ブラウザ)が多くの役割を担います。サーバーとの通信は主にAPIを介してデータのやり取りを行うだけで、ユーザーの状態やUI設定などはクライアントで直接管理されることが多いです。
この時、データを「どこに」保存するかを決定する必要があり、ブラウザはそのためのいくつかのストレージを提供します。各ストレージの特徴と用途を明確に理解することは、効率的なSPA開発の鍵です。
今日はブラウザの主要なストレージであるクッキー(Cookie)、ローカルストレージ(Local Storage)、セッションストレージ(Session Storage)、そしてIndexedDBについて学びます。
1. クッキー (Cookie)
クッキーはブラウザストレージの元祖です。元々はサーバーとクライアント間の状態を維持(Stateful)するために設計されました。
-
特徴:
-
小容量: 約4KBで、容量制限が非常に小さいです。
-
サーバー送信: 最大の特徴です。クッキーはすべてのHTTPリクエストに自動的に含まれサーバーに送信されます。これはサーバーがクライアントの状態を把握する必要がある時に便利ですが、不必要なデータ送信が性能を低下させる可能性もあります。
-
有効期限:
ExpiresまたはMax-Age属性を通じて有効期限を設定できます。設定しない場合はセッションクッキー(ブラウザ終了時に削除)として動作します。 -
セキュリティオプション:
HttpOnly(JavaScriptアクセス防止)、Secure(HTTPSのみ送信)などのセキュリティ設定ができます。
-
-
主な用途:
-
認証 (Authentication): サーバーが発行したログイン認証トークン(JWT等)を保存し、ユーザーがページを移動するたびにサーバーがユーザーを識別できるようにします。(特に
HttpOnlyオプションとともに使用) -
ユーザー追跡と広告: ユーザーの訪問履歴や行動パターンを追跡するために使用されます。(例:Googleアナリティクス)
-
「今日一日見ない」ポップアップ
-
2. ローカルストレージ (Local Storage)
HTML5で導入されたウェブストレージ(Web Storage) APIの一部です。クッキーの欠点(小容量、自動サーバー送信)を補うために登場しました。
-
特徴:
-
大容量: ブラウザごとに異なりますが、通常5MB〜10MBの十分な容量を提供します。
-
サーバー未送信: ローカルストレージはクライアントにのみデータを保存し、サーバーに自動送信されません。サーバーが知る必要がないデータを保存するのに適しています。
-
永続性: データは永続的に保存されます。ユーザーがブラウザキャッシュを手動で削除するか、JavaScriptコードで
localStorage.removeItem()を呼び出さない限りデータは消えません。 -
簡単なAPI:
localStorage.setItem('key', 'value')、localStorage.getItem('key')など、使いやすいAPIを提供します。(文字列のみ保存可能)
-
-
主な用途:
-
ユーザー設定の保存: ダークモード/ライトモード設定、言語設定など、ユーザーが選択したUI設定を保存する際。
-
非機密データ保存: ユーザーが最後に見たコンテンツのリスト、オートセーブ機能など。
-
データキャッシング: API応答の中で頻繁に変更されないデータをキャッシュし、不必要なリクエストを減らす際。
-
3. セッションストレージ (Session Storage)
ローカルストレージとほぼすべての特徴を共有しますが、データのライフサイクル(Life Cycle)において決定的な違いがあります。
-
特徴:
-
大容量: ローカルストレージと同様に約5MBの容量を提供します。
-
サーバー未送信: クライアントにのみ保存されます。
-
セッションベースのライフサイクル: データは現在のブラウザタブ(またはウィンドウ)に限定されます。タブを閉じると、セッションストレージのすべてのデータは即座に削除されます。
-
データの隔離: 同じドメインでも異なるタブ間でデータが共有されません。
-
-
主な用途:
-
一時データ保存: 現在のタブでのみ有効でなければならない情報を保存する際。
-
一時フォームデータ: あらかじめ段階的に構成された会員登録フォームやアンケート作成時に、ユーザーがタブを閉じる前まで入力した内容を一時保存する用途。
-
リフレッシュ時のデータ保持: ページをリフレッシュしてもデータは保持されるべきですが、タブを閉じると消えるべき時。
-
4. IndexedDB
ローカルストレージ/セッションストレージが単純なKey-Valueストレージであるのに対して、IndexedDBはブラウザ内に存在する本格的なトランザクションデータベースシステムです。
-
特徴:
-
大容量保存: 数百MBから数GBまで、ユーザーのディスクスペースが許される限り(ブラウザポリシーによって異なります)非常に大きなデータを保存できます。
-
多様なデータタイプ: 文字列だけでなく、JavaScriptオブジェクト、ファイル(Blob)、配列などの複雑な構造のデータも保存できます。
-
トランザクション(Transaction)サポート: データの整合性と一致性を保証します。複数の作業を一つの単位として扱うことができます。
-
非同期(Asynchronous) API: IndexedDBのすべての作業は非同期で処理されます。これにより、大容量データの読み書き中でもメインUIスレッドがブロック(Block)されず、アプリの反応性が維持されます。
-
インデックス(Index)サポート: インデックスを作成して特定のフィールドでデータを非常に速く検索できます。
-
-
短所:
- 複雑なAPI:
localStorageに比べてAPIがはるかに複雑で使いにくいです。(このため、Dexie.js、idbなどのラッパー(Wrapper)ライブラリと一緒に使用することが多いです。)
- 複雑なAPI:
-
主な用途:
-
オフラインWebアプリケーション (PWA): ネットワーク接続なしでも動作する必要があるアプリで核心データを保存します。(例:オフライン文書編集アプリ)
-
大規模アプリケーション状態キャッシング: GeminiやChatGPTが過去の会話記録をブラウザに保存したり、複雑なユーザーデータを管理する際に使用されます。
-
ユーザー生成コンテンツの一時保存: ユーザーが作成した長文、画像編集データなどをサーバーにアップロードする前に安全に保存します。
-
5. 一目で比較

四つのストレージの特徴を表にまとめると次のようになります。
| 基準 | クッキー (Cookie) | ローカルストレージ | セッションストレージ | IndexedDB |
|---|---|---|---|---|
| 容量 | ~ 4KB | ~ 5-10MB | ~ 5MB | ~ GB+ (大容量) |
| 有効期限 | 手動設定 | 永続的 | タブ終了時 | 永続的 |
| サーバー送信 | O (自動送信) | X (クライアント専用) | X (クライアント専用) | X (クライアント専用) |
| アクセス範囲 | 同一ドメイン | 同一出所 | 現在タブ | 同一出所 |
| データ形式 | 文字列 | 文字列 | 文字列 | オブジェクト、ファイル、Blob等 |
| API | 同期 (複雑) | 同期 (簡単) | 同期 (簡単) | 非同期 (複雑) |
| 検索機能 | X | X | X | O (インデックス使用) |
6. 結論: 何をいつ使うべきか?
ReactのようなSPAを開発する際、これら4つのストレージの用途を明確に区別するのが良いです。
-
クッキー (Cookie):
-
サーバーが必ず知るべきデータに使用します。(例:セキュリティが重要な認証トークン)
-
HttpOnlyオプションを使用してXSS攻撃からトークンを保護するのが良いです。
-
-
ローカルストレージ (Local Storage):
-
ユーザーがブラウザを再起動しても維持されるべき簡単なデータに使用します。
-
(例:ユーザーUIテーマ設定、言語選択)
-
-
セッションストレージ (Session Storage):
-
現在の作業(タブ)中にのみ必要な一時データに使用します。
-
(例:いくつかの段階のフォーム作成中に一時保存)
-
-
IndexedDB:
-
構造化された大規模データやオフラインサポートが必要な時に使用します。
-
(例:複雑なアプリの状態、会話履歴キャッシング、オフライン文書データ)
-
重要なセキュリティの参考: ローカルストレージ、セッションストレージ、IndexedDBはJavaScriptで簡単にアクセスできます。つまり、XSS(クロスサイトスクリプティング)攻撃に脆弱です。パスワード、個人識別情報、敏感な認証トークンなどはここに絶対に保存すべきではありません。(認証トークンは
HttpOnlyクッキーを使用するのが最も安全です。)
コメントはありません。