On-Page SEO

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.

2 lượt xem Cập nhật: 27/05/2026

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-ControlExpires, bên cạnh các header phụ trợ như ETag, Last-Modified, VaryAge.

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 PaintLargest 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:

  1. Nếu tài nguyên đã có trong cache và còn hạn → dùng ngay, không gửi request.
  2. Nếu hết hạn nhưng có ETag hoặc Last-Modified → gửi request kiểm tra (conditional request, mã 304 nếu chưa thay đổi).
  3. 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:

  1. 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.
  2. Cấu hình trên máy chủ:
    • Nginx: Dùng khối location với expires hoặc add_header:
      location ~* \.(?:css|js|png|jpg|jpeg|gif|ico|svg|woff2)$ { expires 1y; add_header Cache-Control "public, immutable"; }
    • Apache: Dùng .htaccess hoặc cấu hình vhost với mod_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'); } } }));
  3. 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-cacheExpires: 3000-01-01 sẽ khiến trình duyệt ưu tiên Cache-Control).

Lỗi thường gặp

  • Lỗi 1: Dùng max-age=0 hoặc no-cache cho 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ụng no-cache cho nội dung động; dùng public, max-age=31536000 cho tài nguyên tĩnh có versioning.
  • Lỗi 2: Thiếu header Vary: Accept-Encoding khi 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êm Vary: Accept-Encoding nếu bật nén.
  • Lỗi 3: Đặt Expires trướ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ùng Cache-Control thay vì Expires nếu có thể; nếu bắt buộc dùng Expires, đả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-ControlExpires. 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.