Một website có thể tải lại cùng file CSS, ảnh hoặc dữ liệu nhiều lần dù nội dung không thay đổi. HTTP cache giúp tái sử dụng phản hồi đã nhận. Muốn tận dụng cơ chế này, lập trình viên cần trả lời ba câu hỏi: ai được lưu phản hồi, được dùng lại trong bao lâu và khi nào phải kiểm tra phiên bản mới?
1. Cache nằm ở đâu?
Browser cache phục vụ một người dùng; shared cache như CDN có thể phục vụ nhiều người. Một phản hồi dùng được trong trình duyệt chưa chắc phù hợp để chia sẻ cho cả website. Chẳng hạn, trang tài khoản và trang giới thiệu công ty cần chính sách khác nhau. Cookie xuất hiện trong request không tự bảo đảm rằng phản hồi sẽ được coi là riêng tư. Xem hướng dẫn HTTP caching của MDN.
Trong bài này, các giá trị thời gian chỉ là ví dụ thiết kế. Hãy chọn chúng theo mức độ chấp nhận dữ liệu cũ của sản phẩm, thay vì áp dụng cùng một cấu hình cho mọi đường dẫn.
2. Đọc đúng Cache-Control
| Chỉ thị phản hồi | Ý nghĩa thực tế |
|---|---|
max-age=120 | Phản hồi được coi là còn mới khi tuổi cache nhỏ hơn 120 giây. |
s-maxage=600 | Shared cache dùng thời hạn 600 giây, thay cho max-age ở tầng này. |
private | Không cho shared cache lưu; browser cache vẫn có thể lưu. |
public | Cho phép cache dùng chung lưu phản hồi khi các điều kiện liên quan được đáp ứng. |
no-cache | Có thể lưu, nhưng phải xác thực lại thành công trước mỗi lần dùng lại. |
no-store | Yêu cầu cache không lưu phản hồi này. |
No-cache không đồng nghĩa với không lưu. Đây là khác biệt quan trọng khi muốn giảm lượng dữ liệu tải về nhưng vẫn kiểm tra nội dung mới. Định nghĩa nằm trong RFC 9111, phần chỉ thị phản hồi.
3. ETag giúp xác thực phiên bản như thế nào?
ETag là nhãn phiên bản do server cấp cho một representation. Client có thể gửi lại nhãn trong If-None-Match. Nhãn phải thay đổi khi phiên bản nội dung tương ứng thay đổi; không dùng một chuỗi cố định cho mọi response. Tài liệu ETag mô tả cả nhãn mạnh và nhãn yếu có tiền tố W/.
Ví dụ dưới đây là trao đổi HTTP rút gọn cho một danh mục công khai, không có dữ liệu người dùng:
GET /api/public/categories HTTP/1.1
Host: demo.example
HTTP/1.1 200 OK
Cache-Control: public, max-age=120
ETag: "categories-v8"
Content-Type: application/json
{"items":["Guides","Programming"]}
Khi cần xác thực lại, client gửi yêu cầu có điều kiện:
GET /api/public/categories HTTP/1.1
Host: demo.example
If-None-Match: "categories-v8"
HTTP/1.1 304 Not Modified
Cache-Control: public, max-age=120
ETag: "categories-v8"
Với GET, nếu nhãn còn khớp, server có thể trả 304 Not Modified và không gửi body. Client dùng lại body đã lưu. Nếu phiên bản đã đổi, phản hồi bình thường là 200 với body mới. Một lần 304 vẫn cần trao đổi mạng; nó khác việc lấy ngay bản còn mới từ browser cache. Chi tiết tại RFC 9110 về 304.
4. Chọn chính sách theo từng loại tài nguyên
Các cấu hình dưới đây là gợi ý để bắt đầu thử nghiệm, không phải mặc định của mọi framework hoặc CDN:
- HTML cần kiểm tra phiên bản mỗi lần: thử
Cache-Control: no-cachecùng ETag. - Danh mục công khai chấp nhận chậm cập nhật: thử
public, max-age=120, s-maxage=600. Với ví dụ này, cần tính cả cửa sổ dữ liệu cũ tại CDN khi lập kế hoạch cập nhật. - Trang cá nhân có thể lưu tại trình duyệt: cân nhắc
private, no-cache; xác thực và phân quyền vẫn phải thực hiện đúng. - Phản hồi chứa thông tin nhạy cảm không nên lưu: dùng
no-storevà kiểm tra cả cấu hình CDN hoặc service worker.
Không gắn public cho toàn bộ API chỉ để tăng cache hit. Đối chiếu hành vi từng chỉ thị tại tài liệu Cache-Control.
Với file có tên gắn fingerprint nội dung như app.a8c31f.css, có thể dùng public, max-age=31536000, immutable nếu mỗi lần đổi nội dung đều tạo URL mới. immutable cho biết nội dung không đổi trong thời gian còn mới; nó không sửa được lỗi deploy ghi đè file dưới cùng URL. Xem RFC 8246. Hãy giữ file phiên bản cũ đủ lâu để các trang còn tham chiếu đến chúng tiếp tục hoạt động.
5. Đừng bỏ quên Vary và các biến thể nội dung
Nếu cùng URL trả ngôn ngữ khác nhau theo Accept-Language, response có thể cần Vary: Accept-Language. Header này giúp cache phân biệt biến thể theo header request; nó không phải cơ chế phân quyền. Chỉ khai báo những header thực sự ảnh hưởng đến nội dung vì quá nhiều biến thể làm giảm khả năng tái sử dụng. Xem tài liệu Vary.
Trong thiết kế website song ngữ, URL riêng cho mỗi ngôn ngữ thường giúp đội vận hành dễ nhìn ra bản nào đang được cache. Dù chọn cách nào, nên kiểm tra hai ngôn ngữ liên tiếp trên cùng môi trường để phát hiện phản hồi bị dùng nhầm.
6. Kiểm tra bằng một quy trình có thể lặp lại
- Mở Network trong DevTools, kiểm tra response headers và nguồn phản hồi. Khi kiểm tra cache thật, bỏ chọn Disable cache; khi cần đối chiếu không dùng browser cache, bật lại tùy chọn này. Tham khảo Chrome DevTools Network.
- Trên endpoint thử nghiệm do bạn quản lý, gửi GET lần đầu và ghi nhận ETag.
- Gửi lại GET với If-None-Match chứa đúng nhãn vừa nhận; nếu nội dung không đổi và endpoint hỗ trợ validation, mong đợi 304.
- Thay đổi dữ liệu thử nghiệm rồi lặp lại yêu cầu với nhãn cũ: mong đợi 200, body mới và ETag mới.
- Thử bằng hai tài khoản độc lập để chắc chắn dữ liệu cá nhân không bị chia sẻ nhầm.
Ví dụ lệnh cho Bash hoặc zsh; thay URL và ETag bằng giá trị của môi trường thử nghiệm:
curl -sS -D - -o /dev/null 'https://demo.example/api/public/categories'
curl -sS -D - -o /dev/null -H 'If-None-Match: "categories-v8"' 'https://demo.example/api/public/categories'
Curl ở ví dụ này không tự lưu và tái sử dụng body như browser. Mục tiêu là quan sát headers và mã trạng thái. Đừng chỉ dùng HEAD để kết luận luồng GET đã đúng.
7. Đánh giá hiệu quả sau khi triển khai
Lập bảng trước và sau cho cùng nhóm URL: lượng byte truyền, thời gian phản hồi, request đến origin và lỗi hiển thị dữ liệu cũ. Không đặt mục tiêu tăng 304 bằng mọi giá: nếu cache còn mới có thể phục vụ ngay, việc phải xác thực quá thường xuyên vẫn tạo độ trễ. Nếu server phải dựng toàn bộ body rồi mới tính ETag, lượng byte có thể giảm nhưng chi phí xử lý chưa chắc giảm tương ứng.
Bắt đầu với một nhóm tài nguyên công khai, xác minh cả lần tải đầu lẫn lần tải lại, rồi mới mở rộng. Chính sách cache tốt cần đồng thời tiết kiệm tài nguyên, cập nhật đúng kỳ vọng và giữ dữ liệu của từng người dùng ở đúng phạm vi.




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