Giới thiệu về Lưu Trữ Bên Client
Khi xây dựng các ứng dụng web hiện đại, quản lý dữ liệu bên client là rất quan trọng để nâng cao hiệu suất, cho phép chức năng ngoại tuyến và mang đến trải nghiệm người dùng mượt mà. Dù bạn đang lưu trữ sở thích của người dùng, bộ nhớ đệm phản hồi API hay duy trì phiên đăng nhập, lưu trữ bên client cung cấp nhiều tùy chọn để đáp ứng các nhu cầu khác nhau. Bài viết này khám phá các loại lưu trữ bên client chính có sẵn trong trình duyệt, cùng với ví dụ, trường hợp sử dụng và giới hạn để giúp bạn lựa chọn công cụ phù hợp cho ứng dụng web của mình.
1. Cookies
Cookies là gì?
Cookies là các đoạn dữ liệu nhỏ (thường dưới 4KB) được trình duyệt lưu trữ. Chúng thường được sử dụng để theo dõi phiên, xác thực và lưu trữ một số thông tin nhỏ của người dùng. Cookies được gửi kèm với mọi yêu cầu HTTP đến máy chủ, giúp chúng có thể truy cập cả ở phía client và server.
Ví dụ
javascript
// Thiết lập một cookie
document.cookie = "theme=dark; path=/; max-age=86400; Secure; SameSite=Strict";
// Đọc cookie
console.log(document.cookie);
Trong ví dụ này, chúng ta thiết lập một cookie có tên là theme với giá trị dark và thời gian hết hạn trong 24 giờ (max-age=86400). Các cờ Secure và SameSite=Strict tăng cường bảo mật bằng cách đảm bảo cookie chỉ được gửi qua HTTPS và bị giới hạn trong các yêu cầu cùng miền.
Trường hợp sử dụng tốt nhất
- Mã thông báo xác thực: Cookies với cờ
HttpOnlyvàSecurerất phù hợp để lưu trữ an toàn mã thông báo phiên ở phía server. - Theo dõi phiên: Cookies có thể nhớ phiên người dùng giữa các lần tải trang.
- Cá nhân hóa: Lưu trữ các tùy chọn nhẹ như chủ đề hoặc ngôn ngữ mà người dùng đã chọn.
Giới hạn
- Dung lượng lưu trữ nhỏ: Cookies bị giới hạn khoảng 4KB, không phù hợp cho dữ liệu lớn.
- Tác động đến hiệu suất: Cookies được gửi với mọi yêu cầu HTTP, làm tăng tải mạng.
- Rủi ro bảo mật: Nếu không được cấu hình với các thuộc tính
Secure,HttpOnly, vàSameSite, cookies dễ bị tấn công như cross-site scripting (XSS) hoặc cross-site request forgery (CSRF).
2. LocalStorage
LocalStorage là gì?
LocalStorage là một cơ chế lưu trữ dạng key-value đơn giản có thể giữ khoảng 5-10MB dữ liệu (tùy thuộc vào trình duyệt). Dữ liệu được lưu trong LocalStorage sẽ tồn tại cho đến khi bị xóa một cách rõ ràng, ngay cả khi trình duyệt đã đóng. Đây là hình thức lưu trữ bên client phổ biến nhất.
Ví dụ
javascript
// Lưu dữ liệu
localStorage.setItem("theme", "dark");
// Lấy dữ liệu
let theme = localStorage.getItem("theme");
console.log(theme); // Kết quả: "dark"
// Xóa dữ liệu
localStorage.removeItem("theme");
Ở đây, chúng ta lưu trữ sở thích chủ đề của người dùng và lấy nó sau này. Phương thức removeItem sẽ xóa một cặp key-value cụ thể.
Trường hợp sử dụng tốt nhất
- Sở thích người dùng: Lưu trữ các thiết lập như chủ đề, kích thước phông chữ hoặc sở thích ngôn ngữ.
- Bộ nhớ đệm dữ liệu không nhạy cảm: Lưu trữ phản hồi API nhỏ, không nhạy cảm hoặc dữ liệu tĩnh để giảm số lần gọi đến máy chủ.
Giới hạn
- Hoạt động đồng bộ: LocalStorage là đồng bộ, có thể chặn luồng chính cho các thao tác lớn.
- Lỗ hổng XSS: Dữ liệu có thể truy cập qua JavaScript, khiến nó dễ bị tấn công XSS.
- Không lưu trữ dữ liệu nhạy cảm: Tránh lưu trữ thông tin nhạy cảm như mã thông báo hoặc dữ liệu cá nhân mà không được mã hóa.
3. SessionStorage
SessionStorage là gì?
SessionStorage tương tự như LocalStorage nhưng được giới hạn trong một tab trình duyệt và sẽ bị xóa khi tab hoặc trình duyệt đóng. Nó cũng có dung lượng khoảng 5-10MB.
Ví dụ
javascript
// Lưu dữ liệu phiên
sessionStorage.setItem("draft", "Hello world!");
// Lấy dữ liệu phiên
let draft = sessionStorage.getItem("draft");
console.log(draft); // Kết quả: "Hello world!"
// Xóa dữ liệu phiên
sessionStorage.clear();
Ví dụ này lưu trữ một văn bản nháp trong sessionStorage và lấy nó trong cùng một phiên. Phương thức clear xóa tất cả dữ liệu trong sessionStorage.
Trường hợp sử dụng tốt nhất
- Dữ liệu phiên tạm thời: Lưu trữ các đầu vào của biểu mẫu, trạng thái điều hướng hoặc dữ liệu khác liên quan đến một phiên duy nhất.
- Dữ liệu theo tab: Thích hợp cho dữ liệu không nên tồn tại giữa các tab hoặc phiên.
Giới hạn
- Giới hạn tab: Dữ liệu không được chia sẻ giữa các tab trình duyệt, giới hạn việc sử dụng cho ứng dụng đa tab.
- Dung lượng hạn chế: Tương tự như LocalStorage, nó bị giới hạn ở khoảng 5-10MB.
4. IndexedDB
IndexedDB là gì?
IndexedDB là một API cấp thấp, bất đồng bộ để lưu trữ một lượng lớn dữ liệu có cấu trúc, chẳng hạn như đối tượng, tệp và blob. Nó hỗ trợ các truy vấn và giao dịch phức tạp, rất phù hợp cho các ứng dụng tiên tiến như Progressive Web Apps (PWAs).
Ví dụ
javascript
// Mở (hoặc tạo) một cơ sở dữ liệu
let request = indexedDB.open("myAppDB", 1);
request.onupgradeneeded = function(event) {
let db = event.target.result;
db.createObjectStore("notes", { keyPath: "id", autoIncrement: true });
};
request.onsuccess = function(event) {
let db = event.target.result;
// Thêm dữ liệu
let tx = db.transaction("notes", "readwrite");
let store = tx.objectStore("notes");
store.add({ content: "Learn IndexedDB", createdAt: Date.now() });
// Lấy dữ liệu
store.get(1).onsuccess = function(e) {
console.log("Note:", e.target.result);
};
};
Đoạn mã này tạo ra một cơ sở dữ liệu có tên là myAppDB với một kho đối tượng cho các ghi chú. Nó thêm một ghi chú và truy xuất nó theo ID.
Trường hợp sử dụng tốt nhất
- Ứng dụng ngoại tuyến: Lưu trữ các tập dữ liệu lớn cho việc truy cập ngoại tuyến trong PWAs.
- Dữ liệu phức tạp: Quản lý dữ liệu có cấu trúc như các đối tượng JSON, hình ảnh hoặc tệp.
- Lưu trữ quy mô lớn: Xử lý các tập dữ liệu vượt quá dung lượng của LocalStorage hoặc SessionStorage.
Giới hạn
- API phức tạp: API của IndexedDB phức tạp hơn LocalStorage hoặc SessionStorage, yêu cầu việc xử lý giao dịch và sự kiện cẩn thận.
- Xử lý bất đồng bộ: Cần làm quen với promise hoặc các thư viện như Dexie.js để đơn giản hóa việc sử dụng.
5. Cache Storage (Service Workers)
Cache Storage là gì?
Cache Storage được sử dụng bởi Service Workers để lưu trữ các yêu cầu và phản hồi mạng, cho phép chức năng ngoại tuyến và tải trang nhanh hơn. Nó chủ yếu được thiết kế để bộ nhớ đệm các tài sản như HTML, CSS, JavaScript và phản hồi API.
Ví dụ
javascript
// Trong một Service Worker
self.addEventListener("install", event => {
event.waitUntil(
caches.open("v1").then(cache => {
return cache.addAll(["/", "/index.html", "/styles.css", "/app.js"]);
})
);
});
// Lấy từ bộ nhớ đệm
self.addEventListener("fetch", event => {
event.respondWith(
caches.match(event.request).then(response => {
return response || fetch(event.request);
})
);
});
Service Worker này bộ nhớ đệm các tài sản cần thiết trong sự kiện cài đặt và phục vụ chúng từ bộ nhớ đệm trong các sự kiện lấy, cho phép truy cập ngoại tuyến.
Trường hợp sử dụng tốt nhất
- Progressive Web Apps (PWAs): Bộ nhớ đệm các tài sản và phản hồi API để có chức năng ngoại tuyến.
- Tối ưu hóa hiệu suất: Giảm số lần yêu cầu máy chủ bằng cách phục vụ các tài nguyên đã được bộ nhớ đệm.
- Duyệt ngoại tuyến: Cho phép người dùng truy cập nội dung mà không cần kết nối internet.
Giới hạn
- Phụ thuộc vào Service Worker: Cần thiết lập một Service Worker, điều này làm tăng độ phức tạp.
- Tập trung vào tài nguyên: Tốt nhất cho việc bộ nhớ đệm tài sản hơn là dữ liệu người dùng có cấu trúc.
Chọn Lựa Lưu Trữ Phù Hợp
Việc chọn lựa cơ chế lưu trữ bên client phù hợp phụ thuộc vào yêu cầu của ứng dụng của bạn. Dưới đây là hướng dẫn nhanh:
| Trường hợp sử dụng | Tùy chọn tốt nhất |
|---|---|
| Mã thông báo xác thực | Cookies (Secure, HttpOnly) |
| Sở thích người dùng | LocalStorage |
| Dữ liệu phiên tạm thời | SessionStorage |
| Ứng dụng ngoại tuyến / Dữ liệu lớn | IndexedDB |
| Tài sản ngoại tuyến | Cache Storage |
Các Xem Xét và Thực Hành Tốt về Lưu Trữ Bên Client
Khi chọn cơ chế lưu trữ bên client cho các ứng dụng web, hãy xem xét các yếu tố chính sau để đảm bảo hiệu suất tối ưu, bảo mật và trải nghiệm người dùng:
Các yếu tố chính
- Tính bền vững:
- Cookies và LocalStorage tồn tại qua các phiên.
- SessionStorage là cụ thể cho tab và sẽ xóa khi tab đóng.
- Cache Storage phụ thuộc vào vòng đời của Service Worker.
- Bảo mật:
- Tránh dữ liệu nhạy cảm trong LocalStorage/SessionStorage do rủi ro XSS.
- Sử dụng cookies an toàn (với
Secure,HttpOnly,SameSite=Strict) cho xác thực.
- Kích thước lưu trữ:
- Cookies: Giới hạn khoảng 4KB.
- LocalStorage/SessionStorage: ~5-10MB.
- IndexedDB/Cache Storage: Phù hợp cho các tập dữ liệu lớn.
- Hỗ trợ ngoại tuyến:
- IndexedDB và Cache Storage rất thích hợp cho các ứng dụng ngoại tuyến và PWAs.
Thực hành bảo mật tốt
- Cookies: Sử dụng
Secure,HttpOnly, vàSameSite=Strictđể ngăn chặn các cuộc tấn công XSS và CSRF. - LocalStorage/SessionStorage: Tránh dữ liệu nhạy cảm do khả năng truy cập JavaScript và rủi ro XSS.
- IndexedDB: Làm sạch đầu vào và sử dụng API an toàn để tránh tấn công chèn.
- Cache Storage: Xác thực các phản hồi đã được bộ nhớ đệm để ngăn chặn việc phục vụ nội dung lỗi thời hoặc độc hại.
- Mã hóa: Mã hóa dữ liệu nhạy cảm trước khi lưu trữ và giải mã khi truy xuất.