Skip to content

Instantly share code, notes, and snippets.

@kobitoDevelopment
Created November 22, 2025 04:29
Show Gist options
  • Select an option

  • Save kobitoDevelopment/89c204bf447bd3c564ddad6f47342ca7 to your computer and use it in GitHub Desktop.

Select an option

Save kobitoDevelopment/89c204bf447bd3c564ddad6f47342ca7 to your computer and use it in GitHub Desktop.
/*
ブラウザストレージの目的別使い分けサンプル
【認証トークン】→ HttpOnly Cookie
- セキュリティ最優先
- XSS攻撃から保護
- サーバー側で設定
※注意: localStorageに保存しない(XSS攻撃で盗まれる)
【ユーザー設定(テーマ、言語など)】→ localStorage
- 永続的に保存
- 5-10MBまで保存可能
- 即座に読み書き可能(await不要)
※注意: プライベートブラウジングでは動作しない場合あり
【一時的なフォーム入力】→ sessionStorage
- タブを閉じたら消える
- ページ遷移では保持
- セッション内のみ有効
※注意: 別タブ間では共有されない
【大容量データ(画像、動画、大量レコード)】→ IndexedDB
- 数百MB〜GB保存可能
- 非同期処理必須
- 複雑なデータ構造OK
【トラッキング・分析】→ ファーストパーティCookie
- SameSite属性でCSRF対策
- 有効期限設定可能
- クロスサイトで読み取り可能
※注意: 容量制限4KBまで、Secure属性必須(HTTPS環境)
===== 共通の注意事項 =====
・機密データは必ず暗号化を検討する
・ストレージ容量の制限に注意
・エラーハンドリングを必ず実装する
*/
/* 1. Cookieが適している場合 */
// 読み込む場合
function getCookie(name) {
const value = `; ${document.cookie}`;
const parts = value.split(`; ${name}=`);
if (parts.length === 2) return parts.pop().split(";").shift();
}
// 書き込む場合(HttpOnly Cookieはクライアント側から書き込み不可。サーバー側で設定)
function setCookie(name, value, days = 7) {
const expires = new Date(Date.now() + days * 24 * 60 * 60 * 1000).toUTCString();
document.cookie = `${name}=${value}; expires=${expires}; path=/; SameSite=Lax`;
}
/* 2. localStorageが適している場合 */
// 読み込む場合
function loadUserSettings() {
try {
const saved = localStorage.getItem("userSettings");
return saved ? JSON.parse(saved) : null;
} catch (e) {
console.error("Failed to load settings:", e);
return null;
}
}
// 書き込む場合
function saveUserSettings(settings) {
try {
localStorage.setItem("userSettings", JSON.stringify(settings));
} catch (e) {
console.error("Failed to save settings:", e);
}
}
/* 3. sessionStorageが適している場合 */
// 読み込む場合
function restoreFormData() {
const saved = sessionStorage.getItem("tempFormData");
if (saved) {
const data = JSON.parse(saved);
// フォームに復元
Object.keys(data).forEach((key) => {
const input = document.getElementById(key);
if (input) input.value = data[key];
});
// 復元後は削除
sessionStorage.removeItem("tempFormData");
}
}
// 書き込む場合
function saveFormData(formData) {
sessionStorage.setItem("tempFormData", JSON.stringify(formData));
}
/* 4. IndexedDBが適している場合 */
class LargeDataStore {
constructor(dbName = "MyAppDB", version = 1) {
this.dbName = dbName;
this.version = version;
this.db = null;
}
async init() {
return new Promise((resolve, reject) => {
const request = indexedDB.open(this.dbName, this.version);
request.onerror = () => reject(request.error);
request.onsuccess = () => {
this.db = request.result;
resolve();
};
request.onupgradeneeded = (event) => {
const db = event.target.result;
// オブジェクトストアの作成
if (!db.objectStoreNames.contains("files")) {
db.createObjectStore("files", { keyPath: "id" });
}
};
});
}
// 読み込む場合
async getFile(id) {
const transaction = this.db.transaction(["files"], "readonly");
const store = transaction.objectStore("files");
return new Promise((resolve, reject) => {
const request = store.get(id);
request.onsuccess = () => resolve(request.result);
request.onerror = () => reject(request.error);
});
}
// 書き込む場合
async saveFile(id, data) {
const transaction = this.db.transaction(["files"], "readwrite");
const store = transaction.objectStore("files");
return store.put({ id, data, timestamp: Date.now() });
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment