Khái niệm cơ bản về Cookie và Session
Trong giao thức HTTP, bản chất của nó là stateless (không lưu trạng thái). Điều này có nghĩa là mỗi yêu cầu từ trình duyệt gửi đến máy chủ đều độc lập và không giữ lại thông tin từ những lần giao tiếp trước đó. Để giải quyết vấn đề nhận diện người dùng hoặc duy trì trạng thái đăng nhập, chúng ta sử dụng Cookie và Session.
- Cookie: Là dữ liệu được lưu trữ tại trình duyệt (Client-side). Khi trình duyệt gửi request, các cookie liên quan sẽ được đính kèm trong header.
- Session: Là cơ chế lưu trữ thông tin trên máy chủ (Server-side). Mỗi phiên làm việc được định danh bằng một SessionId.
- Mối liên hệ: SessionId thường được lưu trữ trong Cookie của trình duyệt. Khi người dùng gửi request, máy chủ đọc SessionId từ Cookie để truy xuất thông tin tương ứng trong bộ nhớ.
1. Sử dụng HttpServletRequest (Cách truyền thống)
Spring MVC cho phép truy cập trực tiếp vào đối tượng HttpServletRequest của Servlet để lấy danh sách toàn bộ Cookie.
@RestController
@RequestMapping("/v1/cookie")
public class CookieNativeController {
@GetMapping("/list")
public String readCookies(HttpServletRequest request) {
Cookie[] cookies = request.getCookies();
if (cookies != null) {
for (Cookie item : cookies) {
System.out.println("Key: " + item.getName() + " - Value: " + item.getValue());
}
return "Đã nhận được danh sách Cookie.";
}
return "Không có Cookie nào được tìm thấy.";
}
}
Xử lý lỗi NullPointerException khi duyệt Stream
Nếu bạn sử dụng Java Stream API để duyệt danh sách Cookie, hãy cẩn thận với trường hợp request.getCookies() trả về null (khi trình duyệt không gửi bất kỳ cookie nào). Việc gọi trực tiếp Arrays.stream() sẽ gây ra lỗi 500 (Internal Server Error).
@GetMapping("/list-safe")
public String readCookiesSafe(HttpServletRequest request) {
Cookie[] cookies = request.getCookies();
// Kiểm tra null trước khi xử lý
if (cookies != null) {
Arrays.stream(cookies).forEach(c -> {
System.out.printf("Cookie: %s = %s%n", c.getName(), c.getValue());
});
}
return "Hoàn tất kiểm tra.";
}
2. Sử dụng chú thích @CookieValue trong Spring
Nếu bạn chỉ cần lấy một hoặc một vài giá trị Cookie cụ thể, việc sử dụng annotation @CookieValue sẽ giúp mã nguồn ngắn gọn và dễ đọc hơn nhiều so với cách lấy toàn bộ mảng Cookie.
Lấy một giá trị đơn lẻ
Dưới đây là cách ánh xạ trực tiếp một Cookie có tên là session_key vào biến trong phương thức:
@GetMapping("/single")
public String getOneCookie(@CookieValue(value = "session_key", defaultValue = "unknown") String sessionKey) {
return "Giá trị của session_key là: " + sessionKey;
}
Lấy đồng thời nhiều Cookie
Bạn có thể khai báo nhiều tham số với annotation này để nhận các giá trị khác nhau:
@GetMapping("/multi")
public String getMultipleCookies(
@CookieValue("user_id") String userId,
@CookieValue("theme_preference") String theme) {
return String.format("User ID: %s, Giao diện: %s", userId, theme);
}
So sánh hai phương pháp
| Tiêu chí | HttpServletRequest | @CookieValue |
|---|---|---|
| Phạm vi | Lấy được tất cả Cookie hiện có. | Chỉ lấy được các Cookie được chỉ định. |
| Độ phức tạp | Phải duyệt mảng và tìm kiếm thủ công. | Tự động map dữ liệu vào biến. |
| Trường hợp sử dụng | Khi cần xử lý logic phức tạp trên toàn bộ Cookie. | Khi đã biết trước tên Cookie cần lấy. |
Lưu ý: Bạn có thể tự tạo Cookie để kiểm tra logic bằng cách sử dụng Công cụ dành cho nhà phát triển (F12) trên trình duyệt, mục Application -> Cookies, hoặc sử dụng các công cụ như Postman để gửi yêu cầu kèm Header Cookie.