Conditional GET — một cơ chế HTTP cho phép máy khách kiểm tra tính mới của tài nguyên được lưu trong bộ nhớ đệm trước khi tải xuống đầy đủ. Máy khách gửi yêu cầu GET với các tiêu đề If-None-Match (chứa ETag) hoặc If-Modified-Since (chứa ngày) và máy chủ trả về 304 Not Modified mà không có nội dung phản hồi nếu tài nguyên không thay đổi. Theo MDN Web Docs, 2025, các yêu cầu có điều kiện giảm lưu lượng mạng của máy chủ và máy khách. 304 Not Modified là trạng thái HTTP quan trọng để đồng bộ hóa ứng dụng di động hiệu quả.
Những điểm chính
Conditional GET là yêu cầu GET bao gồm một hoặc nhiều tiêu đề có điều kiện, dựa trên đó máy chủ quyết định trả về phản hồi đầy đủ hay chỉ trạng thái 304 Not Modified. Mục tiêu chính là tránh truyền nội dung phản hồi nếu tài nguyên không thay đổi kể từ yêu cầu cuối cùng. Đây là cơ chế lưu trữ đệm HTTP cơ bản được định nghĩa trong RFC 7232.
Đối với ứng dụng di động, Conditional GET là một trong những cách hiệu quả nhất để tối ưu hóa lưu lượng mạng. Một kịch bản điển hình: khi mở ứng dụng, máy khách gửi một loạt yêu cầu GET có điều kiện để tải nguồn cấp dữ liệu, hồ sơ và cài đặt. Nếu dữ liệu không thay đổi, ứng dụng nhận được 304 và sử dụng bản sao cục bộ. Quá trình này mất mili giây thay vì giây và không tiêu tốn dữ liệu di động.
Theo Google Web Fundamentals (2025), việc triển khai các yêu cầu GET có điều kiện trong ứng dụng di động giảm thời gian tải trung bình 40–60% cho các lần truy cập lặp lại và giảm sử dụng lưu lượng 70–90% cho các trang có cập nhật không thường xuyên. Hiệu quả đặc biệt rõ rệt trên các kết nối chậm (3G, Edge), nơi mỗi byte đều quan trọng.
Quy trình bao gồm ba bước. Đầu tiên — máy khách gửi yêu cầu GET thông thường, máy chủ trả về tài nguyên cùng với các tiêu đề lưu trữ đệm (ETag, Last-Modified). Thứ hai — máy khách lưu tài nguyên và bộ xác thực của nó vào cục bộ. Thứ ba — khi yêu cầu lặp lại, máy khách gửi GET với If-None-Match (cho ETag) và/hoặc If-Modified-Since (cho Last-Modified). Máy chủ kiểm tra bộ xác thực và phản hồi 304 nếu tài nguyên không thay đổi, hoặc 200 với dữ liệu mới.
Máy chủ sử dụng ưu tiên ETag hơn Last-Modified khi cả hai tiêu đề đều có mặt. Điều này là do ETag cung cấp xác thực chính xác hơn — băm nội dung thay đổi với bất kỳ sửa đổi nào, trong khi Last-Modified có độ phân giải một giây. Nếu ETag khớp, máy chủ ngay lập tức trả về 304 mà không kiểm tra Last-Modified.
Ví dụ về một chu kỳ Conditional GET hoàn chỉnh trong chuỗi yêu cầu:
// Bước 1: Yêu cầu đầu tiên — lấy dữ liệu và ETag
GET /api/profile
Response: 200 OK
ETag: "33a64df551425fcc55e"
Body: { "name": "Alice" }
// Bước 2: Lặp lại yêu cầu — với If-None-Match
GET /api/profile
If-None-Match: "33a64df551425fcc55e"
Response: 304 Not Modified
// Nội dung phản hồi không có — sử dụng bản sao cục bộ
Trong yêu cầu thứ hai, máy chủ so sánh ETag từ If-None-Match với băm tài nguyên hiện tại. Nếu khớp, nó trả về 304 mà không có nội dung — máy khách tiếp tục sử dụng dữ liệu được lưu trong bộ nhớ đệm. Đây là bản chất của Conditional GET: lưu lượng tối thiểu với tính mới dữ liệu tối đa.
Yêu cầu GET thông thường luôn trả về phản hồi đầy đủ 200 OK với nội dung. Ngay cả khi tài nguyên không thay đổi, máy chủ vẫn truyền lại tất cả dữ liệu. Điều này chấp nhận được cho các tài nguyên nhỏ hoặc yêu cầu không thường xuyên, nhưng đối với ứng dụng di động với hàng trăm yêu cầu mỗi lần khởi chạy, cách tiếp cận này dẫn đến tiêu thụ lưu lượng và pin quá mức.
Conditional GET thêm chi phí dưới dạng tiêu đề (thường 50–200 byte mỗi yêu cầu) nhưng tiết kiệm kilobyte và megabyte với phản hồi 304. Tài nguyên càng lớn, yêu cầu có điều kiện càng có lợi. Đối với hình ảnh, danh sách dữ liệu và tài liệu JSON từ 10 KB trở lên, Conditional GET có lợi ngay từ yêu cầu lặp lại đầu tiên.
Đặc điểm so sánh của hai cách tiếp cận:
| Tham số | GET thông thường | Conditional GET |
|---|---|---|
| Lưu lượng (không thay đổi) | Phản hồi đầy đủ | Chỉ tiêu đề (~200 byte) |
| Độ trễ | Tải xuống đầy đủ | Mili giây (304) |
| Tải máy chủ | Tạo + truyền | Chỉ kiểm tra ETag |
| Độ phức tạp triển khai | Tối thiểu | Cần lưu trữ ETag |
| Hiệu quả cho dữ liệu lớn | Thấp | Cao |
Hãy xem một triển khai hoàn chỉnh của Conditional GET trong Kotlin sử dụng OkHttp và Room để lưu trữ ETag. Ứng dụng danh sách công việc tải công việc từ máy chủ và sử dụng các yêu cầu có điều kiện để giảm thiểu lưu lượng. Các ETag được lưu trữ trong cơ sở dữ liệu cục bộ để duy trì giữa các phiên.
Kho lưu trữ với Conditional GET trong Kotlin:
class TaskRepository(
private val api: TaskApi,
private val etagDao: EtagDao
) {
suspend fun getTasks(): List<Task> {
val savedEtag = etagDao.getEtag("tasks")
val response = api.fetchTasks(
ifNoneMatch = savedEtag
)
return when (response.code()) {
304 -> taskDao.getAll() // từ bộ nhớ đệm cục bộ
200 -> {
response.header("ETag")?.let {
etagDao.saveEtag("tasks", it)
}
val tasks = response.body() ?: emptyList()
taskDao.replaceAll(tasks)
tasks
}
else -> throw Exception(
"Sync failed: ${response.code()}")
}
}
}
TaskRepository kiểm tra mã phản hồi: 304 có nghĩa là không có thay đổi và dữ liệu được trả về từ bộ nhớ đệm Room cục bộ. Ở 200, ETag mới được lưu và các công việc được cập nhật trong cơ sở dữ liệu cục bộ. Mẫu này là tiêu chuẩn cho các ứng dụng di động đồng bộ hóa qua API REST.
Conditional GET được sử dụng rộng rãi trong các ứng dụng di động để tối ưu hóa đồng bộ hóa dữ liệu. Các kịch bản chính: tải nguồn cấp tin tức (Twitter, Instagram định kỳ truy vấn API với If-None-Match), cập nhật hồ sơ người dùng, tải danh sách thông báo và đồng bộ hóa công việc. Trong mỗi trường hợp, ứng dụng có thể kiểm tra tính mới của dữ liệu mà không cần tải lại.
Đối với ứng dụng ưu tiên ngoại tuyến, Conditional GET đóng vai trò là giai đoạn đầu tiên của đồng bộ hóa. Ứng dụng trước tiên gửi các yêu cầu GET có điều kiện cho tất cả tài nguyên đã được sửa đổi cục bộ kể từ lần đồng bộ cuối cùng. Các tài nguyên có 304 không yêu cầu tải xuống. Sau đó, ứng dụng gửi PUT/POST cho các thay đổi cục bộ. Cách tiếp cận hai giai đoạn này đảm bảo tiêu thụ lưu lượng tối thiểu.
Kết hợp với Giải quyết xung đột, Conditional GET cho phép phát hiện xung đột hiệu quả. Nếu máy khách nhận được 200 với dữ liệu mới (tài nguyên đã thay đổi) nhưng có các thay đổi cục bộ chưa gửi — một xung đột được ghi lại. Máy khách có thể áp dụng LWW (các thay đổi cục bộ bị mất) hoặc khởi chạy Chiến lược hợp nhất để hợp nhất các thay đổi cục bộ và từ xa. Theo Meta Engineering Blog (2025), việc triển khai Conditional GET trong Messenger đã giảm lưu lượng đồng bộ trung bình 73%.
Câu hỏi thường gặp
Conditional GET — yêu cầu HTTP GET với các tiêu đề có điều kiện (If-None-Match, If-Modified-Since). Máy chủ trả về 304 Not Modified nếu tài nguyên không thay đổi hoặc 200 với dữ liệu mới. Đây là cơ chế lưu trữ đệm hiệu quả.
GET thông thường luôn trả về phản hồi đầy đủ với nội dung. Conditional GET thêm tiêu đề kiểm tra phiên bản (ETag, ngày). Nếu dữ liệu không thay đổi, máy chủ phản hồi 304 không có nội dung, tiết kiệm lưu lượng và thời gian tải.
Để lưu trữ đệm hiệu quả, hãy lưu ETag và Last-Modified từ mỗi phản hồi máy chủ vào cơ sở dữ liệu cục bộ. Trong yêu cầu tiếp theo, gửi chúng trong các tiêu đề If-None-Match và If-Modified-Since. Ở 304, sử dụng dữ liệu từ bộ nhớ đệm cục bộ.
Khi phản hồi 304, máy chủ không truyền nội dung phản hồi — chỉ các tiêu đề (~200 byte). Đối với tài nguyên 50 KB, điều này có nghĩa là tiết kiệm 99,6% lưu lượng. Đối với ứng dụng đồng bộ 50 lần mỗi ngày, tiết kiệm lên đến hàng chục megabyte mỗi tháng.
Có, đây là cách tiếp cận tiêu chuẩn cho đồng bộ hóa delta. Máy khách kiểm tra tính mới của mỗi tài nguyên qua Conditional GET, chỉ tải xuống những tài nguyên đã thay đổi và gửi các thay đổi cục bộ. Cách tiếp cận này được sử dụng trong Twitter, Instagram, Telegram và hầu hết các API hiện đại.
Tóm tắt
Chúng tôi sẽ phát triển ứng dụng di động chìa khóa trao tay
IT Sectr tạo các ứng dụng iOS và Android cho các công ty khởi nghiệp và doanh nghiệp từ năm 2017. Chúng tôi sẽ tư vấn và đề xuất giải pháp tốt nhất cho bạn.
Đọc thêm