Lập trình · 24/09/2026

ETag và HTTP 304: Giảm tải truyền dữ liệu cho API đúng cách

Một ứng dụng liên tục tải lại danh mục sản phẩm dù dữ liệu chưa thay đổi sẽ tốn băng thông và thời gian xử lý không cần thiết. ETag giúp client hỏi máy chủ: “Bản tôi đang giữ còn dùng được không?”. Khi phù hợp, máy chủ có thể trả HTTP 304 thay vì gửi lại toàn bộ nội dung.

ETag và HTTP 304: Giảm tải truyền dữ liệu cho API đúng cách

Một ứng dụng liên tục tải lại danh mục sản phẩm dù dữ liệu chưa thay đổi sẽ tốn băng thông và thời gian xử lý không cần thiết. ETag giúp client hỏi máy chủ: “Bản tôi đang giữ còn dùng được không?”. Khi phù hợp, máy chủ có thể trả HTTP 304 thay vì gửi lại toàn bộ nội dung.

Bài viết tập trung vào luồng đọc GET và kiểm thử hành vi cache. Các đoạn HTTP là ví dụ minh họa, không phải kết quả benchmark hoặc cấu hình có thể áp dụng nguyên xi cho mọi API.

1. ETag không phải thời gian hết hạn

Theo RFC 9110, ETag là bộ xác thực cho một representation — một dạng biểu diễn cụ thể của tài nguyên. Nó không bắt buộc là hash hay số phiên bản database. Với GET có If-None-Match khớp representation được chọn, máy chủ trả 304 không có body nội dung thay vì 200 kèm dữ liệu.

Hãy tách hai câu hỏi khi thiết kế: client được phép dùng bản đã lưu trong bao lâu, và sau đó xác minh nó bằng cách nào? ETag giải quyết câu hỏi thứ hai; chính sách freshness nằm ở các chỉ thị cache.

2. Một vòng trao đổi minh họa

GET /api/catalog HTTP/1.1
Host: api.example.com

HTTP/1.1 200 OK
Content-Type: application/json
Cache-Control: private, no-cache
ETag: "catalog-v12"

{"items":[{"id":1,"name":"Keyboard"}]}

Ở lần yêu cầu sau, client có thể gửi validator đã nhận. Đây là ví dụ rút gọn; các header truyền tải thông thường được lược bỏ.

GET /api/catalog HTTP/1.1
Host: api.example.com
If-None-Match: "catalog-v12"

HTTP/1.1 304 Not Modified
Cache-Control: private, no-cache
ETag: "catalog-v12"

Client dùng lại body đã lưu, không coi 304 là một JSON rỗng. Nếu dữ liệu thay đổi, phản hồi thông thường sẽ là 200 với body và validator mới. Client tự viết phải quản lý bản đã lưu; không mặc định mọi thư viện HTTP đều cung cấp cache giống trình duyệt.

3. Chọn Cache-Control theo tính chất dữ liệu

RFC 9111 phân biệt no-cache — cần xác minh trước khi tái sử dụng — với no-store — không lưu phản hồi. private ngăn shared cache lưu phản hồi; nó không mã hóa dữ liệu. max-age quy định thời gian freshness, không phải lời bảo đảm rằng dữ liệu gốc bất biến.

Tình huống minh họaHướng thiết kế cần cân nhắc
Danh mục công khai, chấp nhận trễ ngắnChính sách cache công khai với thời gian freshness được nghiệp vụ chấp thuận
Dữ liệu riêng được phép lưu tại clientPrivate cache, validator và quy tắc xác minh rõ ràng
Nội dung không được phép lưu cacheNo-store; không tối ưu bằng cách cố giữ body để dùng 304

Đừng chọn thời gian cache chỉ vì một con số phổ biến trên mạng. Với giá bán hoặc tồn kho, cần xác định trước mức trễ có thể chấp nhận và nơi kiểm tra lại dữ liệu khi giao dịch.

4. Thiết kế validator theo nội dung thực sự trả về

Đề xuất triển khai: lập danh sách mọi yếu tố có thể đổi body, gồm dữ liệu phụ thuộc, ngôn ngữ, bộ lọc và quyền truy cập. Chỉ dùng số revision khi hệ thống bảo đảm revision thay đổi với mọi cập nhật ảnh hưởng representation. Một timestamp của bảng chính có thể bỏ sót thay đổi từ bảng liên quan.

Tài liệu cache của MDN giải thích vai trò của Vary khi phản hồi phụ thuộc header yêu cầu. Tuy nhiên, đừng dùng mỗi Vary để thay thế thiết kế tách biệt dữ liệu người dùng. Kiểm thử rõ user A không nhận body của user B qua bất kỳ lớp cache nào.

ETag mạnh và yếu có quy tắc so sánh khác nhau; dấu W/ không phải trang trí. Dùng middleware hoặc thư viện đã hỗ trợ conditional request; tránh tự so sánh nguyên chuỗi header vì đầu vào có thể chứa nhiều tag hoặc ký hiệu *. Với thao tác ghi, không suy luận rằng cơ chế GET/304 tự giải quyết xung đột cập nhật.

5. Đo đúng lợi ích và kiểm thử trước khi bật

Nếu server vẫn truy vấn toàn bộ database, tạo JSON rồi mới hash để quyết định 304, chi phí truyền dữ liệu có thể giảm nhưng chi phí dựng phản hồi vẫn còn. Hãy đo riêng dung lượng truyền, thời gian database, CPU và độ trễ; tỷ lệ 304 cao không tự chứng minh hệ thống nhanh hơn.

  • GET đầu tiên trả 200, body đúng và validator hợp lệ.
  • GET có validator hiện tại trả 304 không có body nội dung.
  • Sửa dữ liệu liên quan làm lần xác minh tiếp theo trả nội dung mới.
  • Thay ngôn ngữ, bộ lọc hoặc danh tính không tái sử dụng nhầm bản đã lưu.
  • Người dùng mất quyền vẫn bị từ chối, dù gửi validator cũ.
  • Kiểm tra cả đường đi qua CDN/reverse proxy, không chỉ gọi trực tiếp ứng dụng.

Nên thử trên một endpoint ít rủi ro và có số đo ban đầu. ETag có giá trị khi vừa tiết kiệm truyền tải vừa giữ đúng ngữ nghĩa dữ liệu; nó là một phần của hợp đồng HTTP, không phải nút bật hiệu năng dùng chung cho mọi API.

Thảo luận

Bình luận 0

Đăng nhập để bình luận

Bạn cần có tài khoản để tham gia thảo luận và trả lời độc giả khác.

Đăng nhậpĐăng ký

Chưa có bình luận. Hãy là người đầu tiên chia sẻ ý kiến.