Bộ nhớ đệm HTTP, Cache-Control và CDN: cách đặt để website nhanh mà không hiện nội dung cũ

Cách đặt Cache-Control cho từng loại nội dung, vai trò của CDN, cách làm mới đệm và kiểm tra bằng curl. Dựa trên MDN, các RFC, tài liệu Vercel và Cloudflare.
Website có thể nhanh hơn chỉ nhờ cấu hình header, nếu trình duyệt và CDN được phép dùng lại những gì đã tải. Nhưng cấu hình sai khiến khách thấy giá cũ sau khi đã cập nhật, và tệ hơn là thấy nội dung của người khác.
Bài này giải thích các chỉ thị Cache-Control, cách chọn giá trị theo loại nội dung, vai trò của CDN, cách làm mới đệm và cách kiểm tra. Nguồn chính là MDN, các RFC, tài liệu Vercel và Cloudflare, đối chiếu đến ngày 23/10/2026.
Click Star đã có bài riêng về Core Web Vitals, tối ưu ảnh và INP.
Điểm chính
- Bộ nhớ đệm HTTP có 2 loại: cache riêng (thường là trình duyệt) và cache chung (proxy, CDN). Nội dung theo người dùng phải đánh dấu
private, vì cookie không tự làm phản hồi thành riêng tư. - Thiếu Cache-Control không có nghĩa là không đệm, vì cache được phép tự ước tính thời hạn. Hãy đặt Cache-Control tường minh.
- Tệp có mã băm trong tên đặt
public, max-age=31536000, immutable. HTML thì dùngno-cachekèm ETag, hoặc cho CDN thời hạn riêng bằng s-maxage hay CDN-Cache-Control. no-cachelà được lưu nhưng phải kiểm chứng lại trước khi dùng, cònno-storelà đừng lưu. 2 chỉ thị này dễ bị nhầm với nhau.- Máy chủ không xóa được bản đã lưu ở máy trung gian; Clear-Site-Data: cache chỉ xóa cache trình duyệt. CDN làm mới được bằng purge hoặc invalidate, còn tệp tĩnh thì đổi URL theo nội dung.
- Hãy kiểm tra bằng curl: đọc Cache-Control, Age và cờ trạng thái của CDN, rồi thử cả khi có cookie.

Bộ nhớ đệm HTTP là gì và nằm ở đâu
Theo MDN (sửa đổi 14/8/2026), bộ nhớ đệm HTTP lưu phản hồi rồi dùng lại cho các yêu cầu sau. Phản hồi đến từ nơi gần khách hơn, và máy chủ gốc không phải truy vấn cơ sở dữ liệu hay dựng giao diện lại.
MDN phân biệt cache riêng và cache chung. Cache riêng gắn với từng máy khách, điển hình là trình duyệt, nên có thể lưu phản hồi cá nhân hóa. Cache chung nằm giữa khách và máy chủ, lưu bản dùng cho nhiều người, như proxy và CDN.
Phản hồi tươi, cũ và được kiểm chứng lại thế nào
Theo MDN, phản hồi đã lưu có 2 trạng thái: tươi (dùng lại được) và cũ (hết hạn), tính theo tuổi kể từ lúc máy chủ gốc tạo ra nó. Với Cache-Control: max-age=604800 (1 tuần), phản hồi tươi trong 7 ngày. Nếu 1 cache chung đã giữ nó 1 ngày, nó gửi kèm Age: 86400, và trình duyệt chỉ còn 518400 giây tươi.
Khi đã cũ, cache hỏi lại máy chủ bằng yêu cầu có điều kiện (If-None-Match đi với ETag, If-Modified-Since đi với Last-Modified). Nếu không đổi, máy chủ trả 304 Not Modified không kèm nội dung và bản đã lưu lại được coi là tươi.
Nếu không có Cache-Control, RFC 9111 (IETF, 6/2022) vẫn cho cache tự ước tính thời hạn, với phần điển hình là 10% khoảng thời gian kể từ Last-Modified. web.dev (cập nhật 5/11/2018) cũng nói bỏ Cache-Control không tắt đệm.
Các chỉ thị Cache-Control và chỗ dễ nhầm

Theo MDN (sửa đổi 17/9/2026), max-age=N nghĩa là phản hồi tươi trong N giây kể từ lúc được tạo ra ở máy chủ gốc. s-maxage chỉ áp cho cache chung, bị trình duyệt bỏ qua và ghi đè max-age đối với cache chung.
no-cache cho phép lưu nhưng bắt buộc kiểm chứng trước mỗi lần dùng lại. no-store yêu cầu mọi cache không lưu phản hồi. private chỉ cho phép lưu ở cache riêng như trình duyệt.
MDN lưu ý no-store không xóa bản đã lưu trước đó cho cùng URL, và nếu dùng tràn lan sẽ mất lợi thế của trình duyệt như bộ nhớ đệm lùi tiến (bfcache). MDN khuyên ưu tiên no-cache kèm private.
immutable (RFC 8246, IETF, 9/2017) báo rằng nội dung không đổi khi còn tươi, nên máy khách khỏi kiểm chứng lại khi người dùng tải lại trang.
stale-while-revalidate (RFC 5861, đệ trình độc lập, 5/2010, loại thông tin, không phải tiêu chuẩn Internet) cho cache trả ngay bản cũ trong số giây chỉ định, trong khi kiểm chứng ở nền.
Theo web.dev (cập nhật 18/7/2019), Chrome 75 và Firefox 68 hỗ trợ chỉ thị này, trình duyệt không hỗ trợ sẽ bỏ qua.
Chọn giá trị theo loại nội dung

Tệp có mã băm hoặc số phiên bản trong tên (JS, CSS, ảnh). MDN gọi đây là cache busting: URL đổi mỗi khi nội dung đổi, nên đặt được public, max-age=31536000, immutable kèm ETag. public chỉ cần khi yêu cầu có Authorization.
HTML công khai, giống nhau với mọi người. Địa chỉ trang không gắn được mã băm, nên MDN gợi ý no-cache kèm ETag hoặc Last-Modified: trình duyệt luôn hỏi lại và thường nhận 304 nhỏ gọn.
Riêng trên Vercel, tài liệu (14/9/2026) gợi ý max-age=0, s-maxage=86400 cho trang giống nhau với mọi khách, và max-age=120, s-maxage=86400 cho nội dung ít đổi như blog. Với giá trị sau, khách quay lại có thể thấy nội dung cũ tới 120 giây.
Trang theo người dùng và dữ liệu nhạy cảm. MDN dùng no-cache, private, Vercel gợi ý private, max-age=0: CDN và proxy không được lưu. Với dữ liệu nhạy cảm hoặc đổi từng giây, Vercel khuyến nghị no-store.
Theo cách đọc của Click Star, giá trị của MDN và Vercel không mâu thuẫn mà ở 2 tầng: khi Cache-Control là header đệm duy nhất, Vercel đọc s-maxage rồi gỡ nó khỏi phản hồi gửi trình duyệt.
CDN thay đổi gì
RFC 9213 (IETF, 6/2022) định nghĩa header CDN-Cache-Control chỉ nhắm vào cache của CDN. Ví dụ trong RFC: Cache-Control: max-age=60, s-maxage=120 cùng CDN-Cache-Control: max-age=600 nghĩa là CDN coi tươi 600 giây, cache chung khác 120 giây, cache còn lại 60 giây.
Vercel hỗ trợ Vercel-CDN-Cache-Control (chỉ tác động Vercel) và CDN-Cache-Control, ưu tiên theo thứ tự đó rồi tới Cache-Control. Mặc định phản hồi từ Function là public, max-age=0, must-revalidate, tức CDN không đệm và trình duyệt phải kiểm chứng lại.
Vercel không lưu phản hồi có set-cookie, yêu cầu có Authorization, hay phản hồi có private, no-cache, no-store hoặc Vary nêu Cookie (tài liệu 14/9/2026).
Cloudflare khác Vercel ở mặc định. Theo tài liệu Cloudflare (14/9/2026), mặc định CDN chỉ đệm theo đuôi tệp chứ không theo kiểu MIME, và mặc định không đệm HTML hay JSON.
Cùng một header, hành vi có thể khác
Tài liệu Cloudflare về kiểm chứng lại (29/9/2026) nói khi bật Origin Cache Control, s-maxage mang ngữ nghĩa proxy-revalidate theo RFC 9111, nên đi cùng stale-while-revalidate thì Cloudflare không trả bản cũ. Họ đề xuất max-age kèm stale-while-revalidate và Edge Cache TTL riêng.
Tài liệu Vercel lại dùng s-maxage=1, stale-while-revalidate=59 làm ví dụ phục vụ bản cũ khi làm mới ở nền. Vì vậy hãy thử cấu hình trên đúng CDN.
Xóa và làm mới bộ nhớ đệm
Theo MDN, không có cách xóa bản đã lưu ở máy chủ trung gian với max-age dài, vì yêu cầu sau không còn tới máy chủ. Clear-Site-Data: cache chỉ xóa cache trình duyệt.
Với CDN có công cụ chủ động. Tài liệu Vercel về purge (3/9/2026) mô tả cache tag. Invalidate đánh dấu bản đã lưu là cũ: yêu cầu kế tiếp nhận ngay bản cũ còn việc làm mới chạy ở nền. Delete buộc yêu cầu kế tiếp chờ máy chủ gốc và có thể gây cache stampede, tức nhiều yêu cầu cùng dồn về máy chủ gốc.
Cloudflare cho purge theo URL (cách họ khuyến nghị), tag, tiền tố, hostname hoặc toàn bộ. Tài liệu (29/9/2026) nói phản hồi 200 chỉ xác nhận lệnh đã được nhận. Muốn kiểm tra, hãy gọi lại tài nguyên và xem CF-Cache-Status không còn là HIT.
2 lỗi nặng: nội dung cũ và dữ liệu riêng tư
Nội dung cũ xảy ra, theo cơ chế MDN mô tả, khi HTML hoặc tệp không đổi tên bị đặt thời hạn dài, hoặc CDN giữ bản cũ mà không ai làm mới.
Dữ liệu riêng tư là lỗi rủi ro hơn. MDN cảnh báo quên private ở phản hồi cá nhân hóa có thể khiến nó bị lưu ở cache chung và dùng lại cho nhiều người.
Cloudflare mô tả tấn công Web Cache Deception (tài liệu 6/5/2026): URL trông như tệp tĩnh (ví dụ đuôi .jpg) nhưng trả trang cá nhân hóa, và bản bị lưu có thể bị lấy. Tính năng Cache Deception Armor, khi được bật, kiểm tra đuôi tệp có khớp Content-Type.
Suy luận của Click Star, không phải thử nghiệm: vì Cloudflare đệm theo đuôi tệp, kể cả CSV, tệp xuất dữ liệu theo từng người nên trả private hoặc no-store.
Cách kiểm tra bằng curl

Lệnh sau gửi yêu cầu GET, bỏ thân phản hồi và in header. Hãy chạy 2 lần liên tiếp để so sánh.
curl -s -o /dev/null -D - https://example.com/
Đọc Cache-Control, Age và cờ của CDN. Vercel dùng x-vercel-cache với các giá trị HIT, MISS, STALE, PRERENDER, REVALIDATED, BYPASS (tài liệu 11/8/2026). Cloudflare dùng CF-Cache-Status với các giá trị như HIT, MISS, EXPIRED, STALE, BYPASS, REVALIDATED, UPDATING, DYNAMIC (tài liệu 4/9/2026).
Bước hay bị bỏ: thử lại với cookie đăng nhập, vì trang cá nhân không được trả HIT cho người khác. Cách thử này do Click Star đề xuất.
Ý nghĩa với doanh nghiệp Việt Nam
Click Star không có số đo cho website Việt Nam về chủ đề này; phần dưới là suy luận từ cơ chế đã nêu.
Với trang đích chạy quảng cáo, giá và khuyến mãi đổi thường xuyên: HTML no-cache kèm ETag cho cập nhật ngay, còn tệp tĩnh có mã băm thì cache lâu. Với cổng khách hàng hoặc trang quản trị, rủi ro chính là lộ dữ liệu chứ không phải tốc độ, nên mặc định private hoặc no-store.
Đánh giá của Click Star. Đệm giảm tải cho máy chủ gốc và rút ngắn đường đi của dữ liệu, nhưng lỗi ở đây thường âm thầm: sai thì khách thấy nội dung cũ mà không có thông báo lỗi nào. Nên mặc định thận trọng, mở rộng từng loại nội dung có bằng chứng, và đo trước sau.
Về lợi ích liên quan: Click Star làm dịch vụ thiết kế website chuẩn SEO tải nhanh. Nhận định trên chỉ dựa vào tài liệu đã nêu.
Lộ trình 14 ngày và cách đo (khung tham khảo của Click Star)
Khung này do Click Star đề xuất, không lấy từ nguồn ngoài và không kèm ngưỡng chuẩn.
- Ngày 1 đến 2: lập danh sách khoảng 10 URL tiêu biểu (trang chủ, bài viết, JS và CSS, ảnh, API, trang đăng nhập) và ghi Cache-Control, Age, cờ CDN hiện tại.
- Ngày 3 đến 5: bảo đảm tệp tĩnh có mã băm trong tên rồi đặt
public, max-age=31536000, immutable. - Ngày 6 đến 10: đặt chính sách cho HTML và API theo bảng ở trên, kiểm tra Vary và Set-Cookie, rồi thử các trang cá nhân bằng cookie.
- Ngày 11 đến 14: viết quy trình purge cho giá và khuyến mãi rồi theo dõi tỷ lệ HIT và MISS, số yêu cầu tới máy chủ gốc và số lần khách báo thấy nội dung cũ, so với trước khi đổi.
Những sai lầm thường gặp
- Không đặt Cache-Control, rồi để trình duyệt và CDN tự đoán thời hạn.
- Nhầm
no-cachevớino-store, hoặc dùngno-storecho cả trang thường và mất bfcache. - Đặt max-age dài cho tệp có tên cố định, rồi không có cách buộc khách tải bản mới.
- Quên
privateở trang cá nhân hóa, hoặc tin rằng cookie đã đủ để cache chung không lưu. - Sao chép cấu hình stale-while-revalidate giữa các CDN mà không thử, dù cùng header có thể cho hành vi khác nhau.
- Vary theo User-Agent hoặc Cookie: MDN nói User-Agent làm giảm mạnh tỷ lệ dùng lại, còn Vercel không lưu phản hồi Vary theo Cookie.
- Tin phản hồi 200 của lệnh purge là đã xong, thay vì kiểm tra lại cờ trạng thái của CDN.
Điều chưa biết
Click Star chưa có số đo về tỷ lệ website Việt Nam cấu hình Cache-Control đúng, hay mức tăng tốc cụ thể từ đệm. Hướng dẫn ở đây dựa trên tài liệu của nhà cung cấp, không phải thử nghiệm của Click Star.
Một số nguồn đã cũ: web.dev về HTTP Cache cập nhật 5/11/2018, về stale-while-revalidate 18/7/2019. Click Star chưa đọc bảng tương thích trình duyệt hiện hành cho immutable và stale-while-revalidate.
Hai trang Cloudflare nói khác nhau về no-cache và max-age=0: trang Default cache behavior xếp chúng vào nhóm không đệm, trang Cache responses nói bật Origin Cache Control (mặc định Free, Pro, Business) thì vẫn lưu và kiểm chứng lại, tắt (mặc định Enterprise) thì bỏ qua đệm. Click Star chưa thử thực tế và chưa xem CDN nào khác.
Bài liên quan
Cần tư vấn cụ thể cho doanh nghiệp?
Click Star giúp anh/chị xây dựng giải pháp phù hợp ngành nghề và quy mô. Trả lời mọi câu hỏi trong giờ làm việc.



