HTTP Cache Headers
Các header như Cache-Control và Expires giúp kiểm soát cách trình duyệt và CDN lưu trữ tài nguyên tĩnh.
HTTP Cache Headers là gì?
HTTP Cache Headers là các dòng thông tin được gửi kèm trong phản hồi HTTP từ máy chủ về trình duyệt hoặc CDN (mạng phân phối nội dung), nhằm chỉ định cách lưu trữ, tái sử dụng và làm mới tài nguyên tĩnh như hình ảnh, CSS, JavaScript, phông chữ hay file JSON. Hai header quan trọng nhất là Cache-Control và Expires, bên cạnh các header phụ trợ như ETag, Last-Modified, Vary và Age.
Chúng không phải là công cụ tối ưu tốc độ trực tiếp, mà là cơ chế kiểm soát hành vi lưu cache — giúp trình duyệt biết rõ: "Có nên tải lại file này không? Tải khi nào? Lưu bao lâu? Lưu ở đâu?".
Tại sao quan trọng trong SEO?
Google và các công cụ tìm kiếm xếp hạng trang web nhanh hơn là một yếu tố xếp hạng rõ ràng. HTTP Cache Headers ảnh hưởng trực tiếp đến:
- Tốc độ tải trang lần 2 trở đi: Khi người dùng quay lại, trình duyệt lấy tài nguyên từ bộ nhớ đệm thay vì gọi lại máy chủ → giảm thời gian render, tăng Core Web Vitals (đặc biệt là First Contentful Paint và Largest Contentful Paint).
- Tải trọng máy chủ: Giảm số lượng yêu cầu tới backend → hạ chi phí vận hành, tăng khả năng chịu tải, tránh lỗi 503/504 khi có lưu lượng cao.
- Hành vi thu thập dữ liệu của bot: Googlebot cũng tuân thủ cache headers. Nếu tài nguyên JS/CSS bị chặn cache quá ngắn hoặc không cache, bot có thể tải lại nhiều lần, làm chậm quá trình lập chỉ mục — đặc biệt với site lớn.
- Hiệu suất trên mạng di động: Người dùng 3G/4G thường có băng thông hạn chế; cache hiệu quả giúp tiết kiệm dữ liệu và giảm giật lag khi cuộn trang.
Cách hoạt động
Khi trình duyệt yêu cầu một tài nguyên (ví dụ: /css/main.css), máy chủ trả về mã trạng thái (200 OK) kèm các header. Trình duyệt đọc các header này để quyết định:
- Nếu tài nguyên đã có trong cache và còn hạn → dùng ngay, không gửi request.
- Nếu hết hạn nhưng có
ETaghoặcLast-Modified→ gửi request kiểm tra (conditional request, mã 304 nếu chưa thay đổi). - Nếu không có cache hoặc bị cấm cache (
no-store) → luôn tải mới.
Quy trình này áp dụng cho cả trình duyệt người dùng và các lớp trung gian như CDN, reverse proxy (Varnish, Nginx), hoặc bộ nhớ đệm của nhà cung cấp dịch vụ internet (ISP).
Hướng dẫn thực hiện
Dưới đây là các bước thiết lập cache headers đúng cách cho website WordPress, static site hoặc ứng dụng Node.js/Nginx:
- Xác định loại tài nguyên: Phân nhóm theo chu kỳ cập nhật — ví dụ:
- Tài nguyên không thay đổi: logo.png, font.woff2, vendor.min.js → cache lâu (1 năm).
- Tài nguyên thay đổi định kỳ: main.css, app.js → cache ngắn hơn (1 tuần), kết hợp tên file có hash (ví dụ:
main.a1b2c3.css). - Tài nguyên nhạy cảm: login.html, dashboard.json → tắt cache hoặc dùng
no-cache+ validation.
- Cấu hình trên máy chủ:
- Nginx: Dùng khối
locationvớiexpireshoặcadd_header:location ~* \.(?:css|js|png|jpg|jpeg|gif|ico|svg|woff2)$ { expires 1y; add_header Cache-Control "public, immutable"; }
- Apache: Dùng
.htaccesshoặc cấu hình vhost vớimod_expires:ExpiresByType text/css "access plus 1 week" Header set Cache-Control "public, max-age=604800, immutable"
- Node.js (Express): Dùng middleware
res.set():app.use('/static', express.static('public', { maxAge: '1y', setHeaders: (res, path) => { if (path.endsWith('.js') || path.endsWith('.css')) { res.set('Cache-Control', 'public, max-age=31536000, immutable'); } } }));
- Nginx: Dùng khối
- Kiểm tra kết quả: Dùng DevTools (tab Network → chọn file → xem phần Response Headers), hoặc lệnh
curl -I https://example.com/style.css. Đảm bảo không có mâu thuẫn giữa các header (ví dụ:Cache-Control: no-cachevàExpires: 3000-01-01sẽ khiến trình duyệt ưu tiênCache-Control).
Lỗi thường gặp
- Lỗi 1: Dùng
max-age=0hoặcno-cachecho mọi tài nguyên
→ Hệ quả: Không tận dụng được cache, tăng tải server và làm chậm trải nghiệm người dùng.
Cách khắc phục: Chỉ áp dụngno-cachecho nội dung động; dùngpublic, max-age=31536000cho tài nguyên tĩnh có versioning. - Lỗi 2: Thiếu header
Vary: Accept-Encodingkhi nén Gzip/Brotli
→ Hệ quả: CDN có thể lưu bản nén và bản không nén cùng lúc, gây nhầm lẫn khi trả về cho trình duyệt không hỗ trợ nén.
Cách khắc phục: Luôn thêmVary: Accept-Encodingnếu bật nén. - Lỗi 3: Đặt
Expirestrước ngày hiện tại hoặc sai múi giờ
→ Hệ quả: Trình duyệt coi tài nguyên đã hết hạn ngay lập tức.
Cách khắc phục: DùngCache-Controlthay vìExpiresnếu có thể; nếu bắt buộc dùngExpires, đảm bảo giá trị là thời gian tuyệt đối theo chuẩn RFC 1123 (GMT).
Ví dụ thực tế
Dưới đây là bảng so sánh header cache cho 3 loại tài nguyên phổ biến trên một site thương mại điện tử:
| Tài nguyên | Cache-Control | Expires | Ghi chú |
|---|---|---|---|
| logo.svg | public, max-age=31536000, immutable |
1 năm sau | Có hash trong tên file → an toàn khi dùng immutable |
| product-list.js | public, max-age=604800 |
7 ngày sau | Cập nhật hàng tuần → không dùng immutable để tránh cache lỗi |
| cart-count.json | no-store |
- | Dữ liệu cá nhân, thay đổi theo phiên → không lưu cache |
Câu hỏi thường gặp
Cache-Control và Expires khác nhau thế nào?
Cache-Control là header hiện đại, ưu tiên cao hơn và hỗ trợ nhiều chỉ thị linh hoạt (public, private, immutable, stale-while-revalidate). Expires là header cũ, chỉ nhận giá trị thời gian tuyệt đối (GMT), dễ sai do chênh lệch múi giờ. Hiện nay, nên dùng Cache-Control làm chính; Expires chỉ cần thiết nếu hỗ trợ trình duyệt rất cũ (IE8 trở xuống — hiện chiếm dưới 0.01%).
Có nên dùng stale-while-revalidate không?
Có, nếu bạn muốn cải thiện trải nghiệm người dùng khi tài nguyên hết hạn. Chỉ thị này cho phép trình duyệt dùng bản cache cũ trong khi gửi request nền để cập nhật — người dùng không thấy chậm dù file đã hết hạn. Hỗ trợ trên Chrome 73+, Firefox 72+, Edge 79+. Giá trị đề xuất: stale-while-revalidate=86400 (1 ngày). Tuy nhiên, cần kiểm tra kỹ logic cập nhật phía server để tránh trả về nội dung lỗi khi revalidate.
CDN có tuân thủ Cache Headers không?
Phần lớn CDN (Cloudflare, Cloudfront, BunnyCDN) mặc định tuân thủ Cache-Control và Expires. Tuy nhiên, một số CDN cho phép ghi đè bằng rule riêng (ví dụ: Cloudflare Page Rules). Nếu dùng CDN, cần kiểm tra xem nó có đang bỏ qua hoặc sửa đổi header gốc không — vì điều này có thể vô hiệu hóa toàn bộ chiến lược cache của bạn. Cấu hình CDN nên bổ sung chứ không thay thế việc thiết lập header đúng trên máy chủ gốc.