Chương 8: Cookies, Session và Web Storage
Bối cảnh: Tại sao cần lưu trạng thái?
HTTP là giao thức stateless (phi trạng thái). Điều này có nghĩa là mỗi request từ trình duyệt đến server là hoàn toàn độc lập — server không nhớ bạn là ai sau khi xử lý xong request trước. Ví dụ: sau khi bạn đăng nhập vào Facebook, ngay request tiếp theo (đăng bài) thì server sẽ không biết bạn là ai nếu không có cơ chế lưu trạng thái.
Để giải quyết vấn đề này, web sử dụng 3 cơ chế chính: Cookies, Session, và Web Storage.
1. Cookies
Cookies là gì?
Cookie là một tập tin nhỏ (dưới 4KB) chứa thông tin liên quan đến người dùng, được lưu trên máy của người dùng (client-side) và có thể được quản lý bởi trình duyệt.
3 mục đích chính
| Mục đích | Mô tả | Ví dụ |
|---|---|---|
| Quản lý phiên | Ghi nhớ trạng thái người dùng | Giỏ hàng, thông tin đăng nhập, điểm số game |
| Cá nhân hóa | Lưu tùy chọn giao diện | Ngôn ngữ, theme màu sắc trang web |
| Theo dõi hoạt động | Phân tích hành vi | Tần suất truy cập, trang đã xem |
Cách hoạt động
Luồng hoạt động của cookie diễn ra như sau:
Giải thích chi tiết:
- Lần đầu truy cập, server tạo ra một định danh cho người dùng và gửi kèm trong
Set-Cookiecủa HTTP Response Header. - Trình duyệt nhận cookie và lưu lại trên máy.
- Từ các request tiếp theo, trình duyệt tự động đính kèm cookie vào HTTP Request Header — người dùng không cần làm gì.
Các loại Cookies
HTTP Headers liên quan đến Cookies
Server gửi cookie về client qua Set-Cookie trong Response Header:
HTTP/1.0 200 OK
Set-Cookie: SSID=Ap4PGTEq; Domain=foo.com; Path=/; Expires=Wed, 13 Jan 2021 22:23:01 GMT; Secure; HttpOnlyClient gửi cookie lên server qua Cookie trong Request Header:
GET /page HTTP/1.1
Host: foo.com
Cookie: SSID=Ap4PGTEq; lang=vi-VNCác thuộc tính của Cookie
| Thuộc tính | Mô tả | Ví dụ |
|---|---|---|
Name=Value | Tên và giá trị cookie | ASP.NET_SessionId=abcdjsa |
Expires=date | Ngày hết hạn. Nếu để trống → xóa khi đóng trình duyệt | Expires=Wed, 09 Jun 2021 10:18:14 GMT |
Max-Age=second | Thời gian sống tính bằng giây (ưu tiên hơn Expires nếu cả hai cùng có) | Max-Age=9000 (= 2.5 giờ) |
Path=path | Cookie chỉ gửi khi request đến path này hoặc path con của nó | Path=/ (gửi cho tất cả path) |
Domain=domain | Domain nào được phép nhận cookie | Domain=facebook.com |
Secure | Chỉ gửi cookie qua kết nối HTTPS | Secure |
HttpOnly | Cookie không thể truy cập bằng JavaScript (document.cookie), chỉ server mới đọc được | HttpOnly |
SameSite | Kiểm soát khi nào cookie được gửi theo cross-site request (giúp chống CSRF) | SameSite=Strict / Lax / None |
Làm việc với Cookie bằng JavaScript
Tạo cookie:
// Cách đơn giản
document.cookie = "user=UIT; expires=Wed, 13 Jan 2021 00:00:00 GMT";
// Hàm tổng quát để tạo cookie
function setCookie(cname, cvalue, exdays) {
let d = new Date();
d.setTime(d.getTime() + (exdays * 24 * 60 * 60 * 1000));
let expires = "expires=" + d.toUTCString();
document.cookie = cname + "=" + cvalue + ";" + expires + ";path=/";
}
// Ví dụ sử dụng: lưu cookie tên "username" trong 7 ngày
setCookie("username", "John", 7);Đọc cookie:
// Lấy toàn bộ cookie dưới dạng chuỗi
let allCookies = document.cookie;
// Kết quả: "user=UIT; lang=vi-VN; theme=dark"
// Hàm đọc cookie theo tên
function getCookie(cname) {
let name = cname + "=";
let decodedCookie = decodeURIComponent(document.cookie);
let ca = decodedCookie.split(';');
for (let i = 0; i < ca.length; i++) {
let c = ca[i].trim();
if (c.indexOf(name) === 0) {
return c.substring(name.length, c.length);
}
}
return "";
}
// Ví dụ
let username = getCookie("user"); // "UIT"
Thay đổi cookie (ghi đè bằng cùng tên):
document.cookie = "username=Jane; expires=Thu, 18 Dec 2025 12:00:00 UTC; path=/";Xóa cookie (đặt expires về quá khứ):
document.cookie = "username=; expires=Thu, 01 Jan 1970 00:00:00 UTC; path=/;";2. Session
Session là gì?
Session là một phiên làm việc — một cơ chế lưu trữ thông tin người dùng ở phía server. Khi người dùng truy cập vào ứng dụng web, server tạo ra một “hồ sơ tạm thời” dành riêng cho người đó.
Vòng đời của Session:
- Bắt đầu: Khi client gửi request lần đầu (hoặc sau khi đăng nhập thành công).
- Tồn tại: Xuyên suốt quá trình người dùng dùng ứng dụng, từ trang này sang trang khác.
- Kết thúc: Khi người dùng đóng trình duyệt, hoặc khi session timeout (hết giờ không hoạt động — thường từ 20–30 phút).
Cách Session hoạt động kết hợp với Cookie
Session thường dùng Cookie để truyền Session ID giữa client và server:
Kết quả: Server nhận ra bạn là ai mà không cần bạn gửi lại username/password mỗi lần.
Nên lưu gì vào Session?
Session được lưu trên server — mỗi người dùng chiếm một phần bộ nhớ server. Do đó, cần chọn lọc dữ liệu lưu trữ.
Nên lưu:
- Thông tin đăng nhập (user ID, role, quyền hạn)
- Giỏ hàng (với người dùng chưa đăng nhập)
- Sản phẩm/nội dung đã xem gần đây
- Dữ liệu wizard/form nhiều bước
Không nên lưu:
- Dữ liệu lớn như danh sách sản phẩm, bài viết → gây tốn RAM server
- Mật khẩu (dù đã hash)
- Dữ liệu có thể lấy lại từ database dễ dàng
Session trong PHP
<?php
// Bước 1: Bắt đầu session (phải gọi trước khi output bất kỳ HTML nào)
session_start();
// Bước 2: Lưu dữ liệu vào session
$_SESSION["username"] = "john_doe";
$_SESSION["role"] = "admin";
$_SESSION["cart"] = ["item1", "item2"];
// Bước 3: Đọc dữ liệu từ session
echo "Xin chào " . $_SESSION["username"]; // "Xin chào john_doe"
// Bước 4: Xóa toàn bộ session (đăng xuất)
session_destroy();
?>
Session trong ASP.NET MVC
// Thêm mới (nếu chưa có) hoặc thay thế (nếu đã có)
Session["Username"] = "Huong Lan";
Session["CartCount"] = 3;
// Thêm mới (sẽ lỗi nếu key đã tồn tại)
Session.Add("Role", "Admin");
// Đọc dữ liệu
string name = Session["Username"]?.ToString();
// Lấy ID của session hiện tại
string sessionId = Session.SessionId;
// Xóa một key
Session.Remove("CartCount");
// Xóa toàn bộ session
Session.Abandon();3. Web Storage
Web Storage là gì?
Web Storage là API của HTML5 cho phép ứng dụng web lưu trữ dữ liệu trực tiếp trong trình duyệt của người dùng, hoàn toàn phía client-side. Dữ liệu lưu theo dạng key-value và không bao giờ tự động gửi lên server như cookie.
Hai loại Web Storage
localStorage | sessionStorage | |
|---|---|---|
| Thời hạn | Vĩnh viễn (đến khi user xóa cache) | Mất khi đóng tab |
| Phạm vi | Tất cả tab/cửa sổ cùng origin | Chỉ trong tab hiện tại |
| Dung lượng | ~5–10MB | ~5MB |
| Gửi lên server | Không | Không |
Kiểm tra trình duyệt có hỗ trợ không
if (typeof(Storage) !== "undefined") {
console.log("Trình duyệt hỗ trợ Web Storage!");
// Tiến hành sử dụng localStorage / sessionStorage
} else {
console.log("Trình duyệt không hỗ trợ Web Storage.");
// Dự phòng: dùng cookie hoặc thông báo người dùng
}Các phương thức của Web Storage API
Cả localStorage và sessionStorage đều dùng chung bộ API sau:
| Phương thức | Mô tả |
|---|---|
setItem(key, value) | Lưu một cặp key/value. Nếu key đã tồn tại thì ghi đè |
getItem(key) | Lấy giá trị theo key. Trả về null nếu không tồn tại |
removeItem(key) | Xóa một cặp key/value theo key |
clear() | Xóa tất cả key/value trong storage |
key(n) | Lấy tên của key ở vị trí thứ n (dùng để duyệt qua tất cả key) |
length | Số lượng key/value đang được lưu |
localStorage — Lưu trữ vĩnh viễn
// === Lưu dữ liệu ===
// Cách 1: setItem (khuyến nghị)
localStorage.setItem("theme", "dark");
localStorage.setItem("language", "vi");
// Cách 2: dot notation
localStorage.theme = "dark";
// Cách 3: bracket notation
localStorage["theme"] = "dark";
// === Lưu object (cần JSON.stringify) ===
const user = { name: "John", age: 25 };
localStorage.setItem("user", JSON.stringify(user));
// === Đọc dữ liệu ===
let theme = localStorage.getItem("theme"); // "dark"
// Đọc object
let storedUser = JSON.parse(localStorage.getItem("user"));
console.log(storedUser.name); // "John"
// === Xóa dữ liệu ===
localStorage.removeItem("theme"); // Xóa một key
localStorage.clear(); // Xóa tất cả
// === Duyệt tất cả key ===
for (let i = 0; i < localStorage.length; i++) {
let key = localStorage.key(i);
let value = localStorage.getItem(key);
console.log(key + ": " + value);
}sessionStorage — Lưu trữ theo phiên
API giống hoàn toàn localStorage, chỉ khác ở vòng đời:
// Lưu dữ liệu form (tránh mất khi refresh trang)
sessionStorage.setItem("draftEmail", "Kính gửi...");
// Lưu bước hiện tại của wizard nhiều bước
sessionStorage.setItem("checkoutStep", "3");
// Đọc lại
let draft = sessionStorage.getItem("draftEmail");
// Khi submit form xong, xóa draft
sessionStorage.removeItem("draftEmail");4. So sánh tổng quan
Session vs Cookies
| Tiêu chí | Session | Cookie |
|---|---|---|
| Nơi lưu trữ | Server | Client (máy người dùng) |
| Dung lượng | Tùy ý (giới hạn bởi RAM/disk server) | Tối đa 4KB |
| Thời hạn | Đến khi đóng trình duyệt hoặc timeout | Tùy thuộc vào Expires/Max-Age |
| Bảo mật | Cao hơn (dữ liệu ở server) | Thấp hơn (dữ liệu ở client, dễ đánh cắp/sửa) |
| Hiệu năng server | Tốn RAM server khi nhiều người dùng | Không tốn tài nguyên server |
| Gửi lên server | Gián tiếp (qua Session ID) | Tự động kèm theo mỗi request |
Cookies vs localStorage vs sessionStorage
| Tiêu chí | Cookies | localStorage | sessionStorage |
|---|---|---|---|
| Dung lượng | 4KB | ~10MB | ~5MB |
| Hỗ trợ HTML | HTML4 + | HTML5 | HTML5 |
| Thời hạn | Do lập trình viên đặt | Vĩnh viễn (đến khi xóa cache) | Đến khi đóng tab |
| Truy cập từ | Bất kỳ tab nào (cùng domain) | Bất kỳ tab nào (cùng origin) | Chỉ trong tab hiện tại |
| Gửi lên server | Có (tự động) | Không | Không |
| Nơi lưu | Browser + Server nhận | Browser only | Browser only |
| JavaScript đọc được | Có (trừ khi HttpOnly) | Có | Có |