Browser Storage cho phép các website lưu trữ dữ liệu trực tiếp trên máy tính của người dùng, giúp website hoạt động nhanh hơn và ghi nhớ thông tin người dùng.
📦 localStorage (Bộ nhớ cục bộ):
🔄 sessionStorage (Bộ nhớ phiên làm việc):
🍪 Cookies (Bánh quy web):
🔧 API (Application Programming Interface):
Giao diện lập trình ứng dụng - bộ công cụ để tương tác với browser storage
📊 Capacity (Dung lượng):
Số lượng dữ liệu tối đa có thể lưu trữ
⏰ Persistence (Tính bền vững):
Thời gian dữ liệu tồn tại (lâu dài hay tạm thời)
🌐 HTTP Request:
Yêu cầu gửi từ trình duyệt lên server (máy chủ)
🎯 Session (Phiên làm việc):
Khoảng thời gian từ khi mở website đến khi đóng tab
🔐 Expiration (Thời gian hết hạn):
Thời điểm dữ liệu sẽ bị xóa tự động
Bảng dưới đây giúp bạn chọn loại storage phù hợp cho từng tình huống cụ thể.
| Loại Storage (Phương thức lưu trữ) |
Dung lượng (Capacity) |
Thời gian tồn tại (Persistence) |
Gửi kèm Request (Auto-send) |
Cách sử dụng (API Methods) |
|---|---|---|---|---|
| 📦 localStorage Bộ nhớ cục bộ |
~5-10MB Lớn nhất |
Vĩnh viễn Đến khi người dùng xóa thủ công |
❌ Không Chỉ ở phía client |
localStorage.setItem(key, value)localStorage.getItem(key) |
| 🔄 sessionStorage Bộ nhớ phiên |
~5-10MB Lớn nhất |
Tạm thời Mất khi đóng tab/cửa sổ |
❌ Không Chỉ ở phía client |
sessionStorage.setItem(key, value)sessionStorage.getItem(key) |
| 🍪 Cookies Bánh quy web |
~4KB Rất nhỏ, mỗi cookie |
Tùy chỉnh Có thể set thời gian hết hạn |
✅ Có Tự động gửi lên server |
document.cookie = "name=value"Phức tạp hơn, cần helper functions |
try-catch để bắt lỗiSử dụng các demo bên dưới để thực hành với localStorage, sessionStorage và Cookies. Mở DevTools để theo dõi changes.
Yêu cầu: Tạo hệ thống lưu trữ preferences của user bằng Cookies (theme, ngôn ngữ, font size).
🎯 Demo text hiển thị preferences của bạn!
Theme: -
Language: -
Font Size: -
Browser Storage có thể bị khai thác bởi hacker thông qua:
document.cookie = "token=abc; Secure"
// ✅ An toàn: Luôn sử dụng try-catch
function safeSetStorage(key, value) {
try {
// Validate input trước khi lưu
if (!key || typeof key !== 'string') {
throw new Error('Key phải là string không rỗng');
}
localStorage.setItem(key, JSON.stringify(value));
return true;
} catch (error) {
console.error('Lỗi khi lưu storage:', error.message);
return false;
}
}
// ✅ An toàn: Có fallback value
function safeGetStorage(key, defaultValue = null) {
try {
const item = localStorage.getItem(key);
return item ? JSON.parse(item) : defaultValue;
} catch (error) {
console.warn('Không thể đọc storage, trả về default:', error.message);
return defaultValue;
}
}
// ✅ An toàn: Secure cookie với đầy đủ flags
function setSecureCookie(name, value, days = 7) {
const expires = new Date();
expires.setTime(expires.getTime() + (days * 24 * 60 * 60 * 1000));
// Chỉ hoạt động trên HTTPS production
const secureFlag = location.protocol === 'https:' ? '; Secure' : '';
document.cookie = `${name}=${encodeURIComponent(value)}; ` +
`expires=${expires.toUTCString()}; ` +
`path=/; ` +
`SameSite=Strict${secureFlag}`;
}
🔍 Nguyên nhân: Lưu quá nhiều dữ liệu, vượt quá limit (~5-10MB)
⚡ Triệu chứng: Console hiển thị "QuotaExceededError"
✅ Cách sửa:
🔍 Nguyên nhân: Private/Incognito mode, hoặc file:// protocol
⚡ Triệu chứng: Storage không hoạt động, SecurityError trong console
✅ Cách sửa:
🔍 Nguyên nhân: Dữ liệu không phải JSON hợp lệ
⚡ Triệu chứng: SyntaxError khi JSON.parse()
✅ Cách sửa:
// 🛡️ Helper class an toàn với đầy đủ error handling
class SafeStorageHelper {
// Kiểm tra xem storage có khả dụng không
static isAvailable(storageType = 'localStorage') {
try {
const storage = window[storageType];
const testKey = '__storage_test__';
storage.setItem(testKey, 'test');
storage.removeItem(testKey);
return true;
} catch (error) {
console.warn(`${storageType} không khả dụng:`, error.message);
return false;
}
}
// Lưu dữ liệu an toàn với validate
static setItem(key, value, storageType = 'localStorage') {
// Kiểm tra availability
if (!this.isAvailable(storageType)) {
console.error(`${storageType} không khả dụng`);
return false;
}
try {
// Validate input
if (!key || typeof key !== 'string') {
throw new Error('Key phải là string không rỗng');
}
const storage = window[storageType];
const serializedValue = JSON.stringify(value);
storage.setItem(key, serializedValue);
console.log(`✅ Đã lưu ${key} vào ${storageType}`);
return true;
} catch (error) {
if (error.name === 'QuotaExceededError') {
console.error('❌ Hết dung lượng storage! Hãy xóa dữ liệu cũ.');
this.cleanup(storageType); // Tự động dọn dẹp
} else {
console.error('❌ Lỗi khi lưu:', error.message);
}
return false;
}
}
// Đọc dữ liệu an toàn với fallback
static getItem(key, defaultValue = null, storageType = 'localStorage') {
if (!this.isAvailable(storageType)) {
console.warn(`${storageType} không khả dụng, trả về default value`);
return defaultValue;
}
try {
const storage = window[storageType];
const item = storage.getItem(key);
if (item === null) {
console.info(`Key "${key}" không tồn tại trong ${storageType}`);
return defaultValue;
}
// Thử parse JSON, fallback về string nếu fail
try {
return JSON.parse(item);
} catch (parseError) {
console.warn('Không thể parse JSON, trả về raw string:', parseError.message);
return item; // Trả về string gốc
}
} catch (error) {
console.error('❌ Lỗi khi đọc:', error.message);
return defaultValue;
}
}
// Dọn dẹp dữ liệu cũ khi hết dung lượng
static cleanup(storageType = 'localStorage', keepCount = 10) {
try {
const storage = window[storageType];
const keys = Object.keys(storage);
if (keys.length > keepCount) {
// Xóa 50% dữ liệu cũ nhất (strategy đơn giản)
const keysToRemove = keys.slice(0, Math.floor(keys.length / 2));
keysToRemove.forEach(key => storage.removeItem(key));
console.log(`🧹 Đã dọn dẹp ${keysToRemove.length} items từ ${storageType}`);
}
} catch (error) {
console.error('❌ Lỗi khi cleanup:', error.message);
}
}
// Debug: In ra thông tin storage
static debugInfo(storageType = 'localStorage') {
if (!this.isAvailable(storageType)) {
console.log(`❌ ${storageType} không khả dụng`);
return;
}
const storage = window[storageType];
const itemCount = storage.length;
let totalSize = 0;
// Tính tổng kích thước
for (let i = 0; i < itemCount; i++) {
const key = storage.key(i);
const value = storage.getItem(key);
totalSize += key.length + (value ? value.length : 0);
}
console.log(`📊 ${storageType} Debug Info:`, {
itemCount,
totalSize: `${totalSize} characters (~${Math.round(totalSize/1024)}KB)`,
estimatedCapacity: '5-10MB',
usage: `${Math.round(totalSize/1024/1024*100)}% (ước tính)`
});
}
}
// 💡 Cách sử dụng:
// SafeStorageHelper.setItem('myKey', {data: 'value'});
// const data = SafeStorageHelper.getItem('myKey', {default: 'fallback'});
// SafeStorageHelper.debugInfo(); // Debug thông tin storage