RFC 9211 Cache-Status chẩn đoán: đọc hit, fwd qua nhiều hop
RFC 9211 Cache-Status chẩn đoán là việc đọc trường Cache-Status trong phản hồi để biết từng tầng cache đã xử lý request thế nào: phục vụ từ bản lưu, chuyển tiếp lên trên, hay xác thực lại. Khi phản hồi đi qua nhiều tầng cache, trường này là một danh sách, và đọc sai thứ tự sẽ cho kết luận ngược. ProxyVN dựng một origin và hai tầng cache tự viết, chạy mười ca qua requests và httpx thật, parse trường bằng http_sfv rồi lập bảng hop nào phục vụ phản hồi.
RFC 9211 Cache-Status chẩn đoán: mục tiêu và phạm vi không lặp
Phần này chốt bài toán, đầu ra và ranh giới.
Bài toán cần giải
Một crawler theo dõi giá thấy dữ liệu cũ vài phút dù website đã cập nhật. Phản hồi có trường Cache-Status với hai thành viên, một ghi hit, một ghi fwd. Người xem đọc thành viên đầu tiên, thấy fwd, kết luận request đã tới origin và dữ liệu là mới. Thực tế thành viên đầu là lịch sử từ lần lưu trước, thành viên cuối mới cho biết ai trả lời lần này.
Đầu ra nghiệm thu
Đầu ra là chuỗi header Cache-Status thật của mười ca qua hai tầng cache, cùng bảng diễn giải: hop nào phục vụ, tầng nào chuyển tiếp với lý do gì, body lấy từ bản lưu nào. Kèm theo là hàm đọc trường theo đúng thứ tự RFC, và bảng đối chiếu với cf-cache-status.
Ranh giới với bài Vary
Bài Vary header khi dùng proxy cache nói cách Vary quyết định khóa cache. Bài này không lặp phần đó. Vary chỉ xuất hiện ở một ca, để thấy cách Cache-Status báo vary-miss. Trọng tâm là đọc chẩn đoán sau khi cache đã quyết định.
Ranh giới với Cloudflare
Bài Cloudflare reverse proxy nói về Cloudflare như một reverse proxy. Header cf-cache-status của Cloudflare là trường riêng, có bộ giá trị riêng. Nó không phải Cache-Status theo RFC 9211. Bài có một phần so sánh để không dùng nhầm từ vựng của bên này cho bên kia.
Giới hạn của lab
Origin và hai tầng cache đều là http.server tự viết, nghe ở 127.0.0.1:9701, 9702, 9703. Quy tắc cache tối giản: lưu theo đường dẫn và Accept-Language, tôn trọng max-age có trần, xác thực lại bằng If-None-Match. Cách gắn Cache-Status do ProxyVN viết theo RFC 9211. Thứ thật trong lab là requests 2.34.2, httpx 0.28.1 và http_sfv 0.9.9.
Ai nên đọc
Người vận hành crawler đi qua proxy có cache hoặc qua CDN. Người cần biết dữ liệu mình lưu là bản mới hay bản cũ. Người cấu hình cache và muốn xuất Cache-Status đúng chuẩn để đội khác đọc được.
Đọc Cache-Status nhiều hop để tìm hit miss forward trong RFC 9211 Cache-Status chẩn đoán
Phần này tóm tắt RFC 9211, chỉ giữ ý cần để đọc trường.
Trường là một List
Theo RFC 9211, Cache-Status là một List theo chuẩn Structured Field Values. Mỗi thành viên đại diện cho một cache đã xử lý request. Thành viên đầu là cache gần origin nhất, thành viên cuối là cache gần người dùng nhất, có thể là cache của chính user agent nếu nó tự thêm.
Thứ tự ngược với trực giác

Thứ tự thành viên
Nhiều người đọc từ trái sang phải và nghĩ thành viên đầu là tầng đầu tiên request gặp. Thực tế ngược lại: request gặp tầng cuối trước, vì tầng cuối gần client nhất. Cache khi thêm thành viên nên giữ giá trị đã có, để có thể debug cả chuỗi. Vì vậy chuỗi đọc từ trái sang phải là đi từ origin ra client.
Ví dụ hai tầng trong RFC
RFC đưa ví dụ OriginCache; hit; ttl=1100 rồi "CDN Company Here"; hit; ttl=545. Diễn giải: cache gần origin đã trả lời một request trước đó từ bản lưu, cache thứ hai lưu phản hồi đó và giờ dùng lại cho request hiện tại. Hai hit không có nghĩa request đi qua cả hai tầng lần này. Chỉ tầng CDN phục vụ.
Tên cache
Mỗi thành viên có định danh là String hoặc Token, tùy triển khai: tên sản phẩm, tên dịch vụ, tên máy, địa chỉ IP hay chuỗi tự sinh. Lab đặt OriginCache cho tầng gần origin và "Edge CDN" cho tầng gần client. Tên có dấu cách phải ở dạng String trong ngoặc kép.
Tham số hit
hit là Boolean. Khi đúng, request được cache đáp ứng, không đi lên trên. Phản hồi do cache sửa từ bản gốc như 304 hay 206 vẫn tính là hit, miễn là không đi lên để xác thực. Bản lưu cũ dùng được mà không đi lên, ví dụ vì origin chết, cũng có thể coi là hit.
Tham số fwd
fwd cho biết request đã đi lên phía origin, giá trị là Token giải thích lý do. RFC sắp các giá trị từ cụ thể nhất tới chung nhất, và cache nên dùng lý do cụ thể nhất mà nó biết. hit và fwd loại trừ nhau, mỗi thành viên chỉ có một trong hai.
Các giá trị của fwd
Bảng dưới gom tám giá trị của fwd theo RFC 9211.
Giá trị |
Ý nghĩa |
|---|---|
bypass |
Cache được cấu hình không xử lý request này |
method |
Ngữ nghĩa method buộc phải chuyển tiếp |
uri-miss |
Không có phản hồi nào khớp URI |
vary-miss |
Có phản hồi khớp URI nhưng không khớp theo Vary |
miss |
Không có phản hồi dùng được, khi không phân biệt được hai loại trên |
request |
Có bản tươi nhưng chỉ thị của request không cho dùng |
stale |
Có bản nhưng đã cũ |
partial |
Có bản nhưng thiếu một phần dải được yêu cầu |
Các tham số khác
fwd-status là Integer, mã mà hop kế tiếp trả cho request đã chuyển, mặc định là mã của phản hồi nếu vắng. ttl là Integer, thời gian tươi còn lại tính bằng giây, có thể âm. stored là Boolean, cache có lưu phản hồi không. collapsed là Boolean, request có được gộp với request khác không. key là String, biểu diễn khóa cache. detail là String hoặc Token, thông tin riêng của triển khai.
Khi nào cache gửi trường
RFC để cache tự quyết khi nào thêm Cache-Status: luôn thêm, chỉ khi được cấu hình, hoặc chỉ khi request có header bật chế độ debug. Vì vậy không thấy trường không có nghĩa là không có cache. Nhiều CDN cần bật tùy chọn mới gửi Cache-Status, hoặc chỉ gửi header riêng của họ.
Lộ thông tin qua Cache-Status
Phần bảo mật của RFC nói kẻ tấn công có thể dùng Cache-Status để dò hành vi cache và suy ra hoạt động của người dùng khác, ví dụ qua tấn công thời gian với dữ liệu nhạy cảm. Cache có thể bỏ trường, chỉ gửi cho client được phép, hoặc bỏ các tham số nhạy cảm như key.
Khi nào không thêm thành viên
RFC nói intermediary không nên thêm thành viên vào phản hồi mà nó tự tạo, kể cả khi có cache, trừ khi phản hồi dựa trên bản lưu như 304 hay 206. Ví dụ proxy tạo 400 vì request hỏng sẽ không thêm Cache-Status. Lab có ca cache tự sinh 502 để kiểm quy tắc này.
Đọc dictionary member và tham số Cache-Status trong RFC 9211 Cache-Status chẩn đoán
Phần này nói cách parse đúng, trước khi dựng lab.
Parse bằng thư viện Structured Field
Tách chuỗi bằng dấu phẩy và dấu chấm phẩy trông đơn giản nhưng hỏng khi tên cache có dấu phẩy trong ngoặc kép, hoặc key chứa ký tự đặc biệt. Lab dùng http_sfv 0.9.9 để parse List theo RFC 9651 về Structured Field Values.
def members(field):
lst = http_sfv.List(); lst.parse(field.encode())
return [(str(m.value), dict(m.params)) for m in lst]
Mỗi thành viên ra một cặp: tên cache và từ điển tham số.
Tham số Boolean không có giá trị
Trong Structured Field, tham số Boolean đúng có thể viết không có giá trị, như hit hay stored. Thư viện parse ra True. Boolean sai viết là ?0, ví dụ collapsed=?0. Parse bằng tay rất dễ coi hit là chuỗi rỗng và bỏ qua.
Trường gửi thành nhiều dòng
Cache có thể thêm thành viên bằng cách nối vào dòng header có sẵn, hoặc bằng một dòng header Cache-Status mới. HTTP cho phép gộp nhiều dòng cùng tên thành một, nối bằng dấu phẩy, và List vẫn đúng thứ tự. Lab cho tầng Edge gửi dòng riêng để kiểm client gộp đúng.
Hàm tìm hop phục vụ
Hàm diagnose đọc từ thành viên cuối ngược về đầu. Gặp hit thì đó là hop phục vụ. Gặp fwd với fwd-status 304 thì body lấy từ bản lưu của tầng đó, tiếp tục tìm ai xác nhận. Nếu mọi thành viên đều fwd, phản hồi đến từ phía sau thành viên đầu, thường là origin.
served, body_from = None, None
for i in range(len(members) - 1, -1, -1):
name, p = members[i]
if p.get("hit") is True:
served = name; break
if p.get("fwd-status") == 304 and body_from is None:
body_from = name
continue
if "fwd" not in p:
served = "khong xac dinh"; break
if served is None:
served = f"upstream phia sau {members[0][0]}"
if body_from:
served = f"body tu ban luu cua {body_from}, xac nhan 304 boi {served}"
Hàm này là mã lab, được chỉnh qua ba lần chạy cho tới khi ra kết luận đúng ở mọi ca.
Vì sao đọc từ cuối
Thành viên cuối là tầng gần client nhất, tầng đầu tiên request gặp. Nếu tầng này hit, request dừng ở đó, mọi thành viên phía trước là lịch sử lưu cùng bản ghi. Đọc từ đầu sẽ thấy lịch sử trước, và kết luận sai như câu chuyện ở đầu bài.
Tham số lạ không làm hỏng parse
Structured Field cho phép tham số bất kỳ có tên hợp lệ. Parser giữ chúng trong từ điển, hàm diagnose chỉ đọc những tham số nó biết. Tham số lạ có thể ghi log để xem sau. Không nên coi tham số lạ là lỗi, vì registry của IANA có thể đã thêm tham số mới.
Thành viên không có hit lẫn fwd
RFC không bắt buộc tham số nào. Một cache có thể chỉ ghi tên. Hàm diagnose gặp thành viên như vậy thì dừng với kết luận không xác định. Đây là cách trung thực: thiếu dữ liệu thì nói thiếu, không đoán.
Tạo response fixture có nhiều cache hop cho RFC 9211 Cache-Status chẩn đoán
Phần này dựng origin và hai tầng cache, chạy thật trên Python 3.12.10.
Origin
Origin trả bảng giá dạng văn bản với Cache-Control max-age=4, Vary Accept-Language, ETag theo phiên bản. Request có If-None-Match khớp thì trả 304. Origin đếm số request nhận được để đối chiếu với kết luận của Cache-Status.
tag = f'"v{VER["n"]}"'
if self.headers.get("If-None-Match") == tag:
self.send_response(304); self.send_header("ETag", tag)
self.send_header("Cache-Control", "max-age=4"); ...
Dấu ba chấm thay cho phần gửi header còn lại, xem mã lab.
Hai tầng cache
OriginCache ở cổng 9702 đứng trước origin, trần ttl 60 giây, nên ttl thực là 4 theo max-age. Edge CDN ở cổng 9703 đứng trước OriginCache, trần ttl 2 giây. Client gọi Edge. Mỗi tầng lưu theo đường dẫn và Accept-Language, xác thực lại bằng If-None-Match khi bản lưu cũ.
Cách gắn thành viên
Khi trả phản hồi, mỗi tầng lấy Cache-Status có sẵn, giữ nguyên, rồi thêm thành viên của mình vào cuối. Khi hit, phản hồi lấy từ bản lưu, nên Cache-Status có sẵn là của lần lưu. Đây là lý do thành viên phía trước có thể là lịch sử.
cs = [v for k, v in headers.items() if k.lower() == "cache-status"]
if sep_line:
for v in cs: self.send_header("Cache-Status", v)
self.send_header("Cache-Status", member)
else:
self.send_header("Cache-Status", ", ".join(cs + [member]))
OriginCache nối vào một dòng, Edge gửi dòng riêng.
Trần ttl ở mỗi tầng
Edge có trần ttl 2 giây dù origin cho max-age 4. Đây là cách mô phỏng CDN được cấu hình giữ bản ngắn hơn chỉ thị của origin. Trần khác nhau giữa hai tầng làm hai bản hết hạn ở thời điểm khác nhau, tạo ra ca 3 và ca 4 với hai cách xác thực khác nhau.
Lý do fwd
Mỗi tầng chọn lý do theo thứ tự. Không có bản nào cho đường dẫn thì uri-miss. Có bản cho đường dẫn nhưng khác Accept-Language thì vary-miss. Có bản tươi nhưng request có Cache-Control: no-cache thì request. Có bản cũ thì stale. POST thì method.
Xác thực lại và 304
Khi bản lưu cũ, tầng cache gửi If-None-Match lên trên. Nhận 304 thì làm mới bản lưu và trả body đã lưu, gắn fwd=stale với fwd-status=304. Bản đầu của lab gửi lại một request thứ hai khi nhận 200 thay vì 304, làm Cache-Status chỉ ghi lần thứ hai. Lab sửa để dùng luôn phản hồi của lần xác thực.
Vì sao tự viết cache
Varnish, Nginx hay CDN thật mỗi thứ có cách gắn Cache-Status riêng, nhiều khi chưa theo RFC 9211. Tự viết cache cho phép bảo đảm định dạng đúng chuẩn để kiểm bộ đọc, và kiểm soát chính xác lúc nào bản lưu hết hạn. Đổi lại, kết quả không nói gì về một sản phẩm cache cụ thể.
Khóa cache khi bật debug
RFC 9211 phần bảo mật nói lộ khóa cache có thể giúp kẻ tấn công đầu độc cache, và chỉ nên gửi key cho client được phép. Lab chỉ thêm tham số key khi request có header X-Debug-Cache: 1. Đây là quy ước của lab, không có trong RFC.
Phân biệt hit, forwarded và thông tin tùy chọn trong RFC 9211 Cache-Status chẩn đoán
Phần này là kết quả mười ca qua requests 2.34.2.
Ca 1, lần đầu

Edge hit, phía trước là lịch sử
Request đầu tiên, cả hai tầng chưa có gì. Origin nhận một request.
Cache-Status: OriginCache; fwd=uri-miss; stored; ttl=4, "Edge CDN"; fwd=uri-miss; stored; ttl=2
=> phuc vu boi: upstream phia sau OriginCache
Hai thành viên đều fwd=uri-miss và stored. Hàm diagnose kết luận phản hồi đến từ phía sau OriginCache, tức origin.
Ca 2, ngay sau đó
Request thứ hai ngay sau đó. Origin không nhận request nào.
Cache-Status: OriginCache; fwd=uri-miss; stored; ttl=4, "Edge CDN"; hit; ttl=1
=> phuc vu boi: Edge CDN
Đây là ca của câu chuyện đầu bài. Thành viên đầu ghi fwd=uri-miss nhưng là lịch sử từ ca 1, lưu cùng bản ghi tại Edge. Thành viên cuối ghi hit, Edge phục vụ.
Ca 3, Edge hết hạn
Sau 2,3 giây, bản của Edge đã cũ, bản của OriginCache còn tươi. Edge gửi If-None-Match lên OriginCache, OriginCache hit và trả 304. Origin không nhận request nào.
Cache-Status: OriginCache; hit; ttl=1, "Edge CDN"; fwd=stale; fwd-status=304; ttl=2
=> phuc vu boi: body tu ban luu cua Edge CDN, xac nhan 304 boi OriginCache
Body đến từ bản lưu của Edge. OriginCache chỉ xác nhận bản đó còn đúng.
Ca 4, cả hai hết hạn
Sau 4,3 giây nữa, cả hai bản đều cũ. Edge xác thực với OriginCache, OriginCache xác thực với origin, origin trả 304. Origin nhận một request.
Cache-Status: OriginCache; fwd=stale; fwd-status=304; ttl=4, "Edge CDN"; fwd=stale; stored; ttl=2
=> phuc vu boi: body tu ban luu cua OriginCache, xac nhan 304 boi upstream phia sau OriginCache
Edge nhận 200 từ OriginCache, không phải 304, vì OriginCache trả lại body đã lưu cho Edge. Vậy nên Edge ghi fwd=stale; stored, không có fwd-status.
Thời gian ttl đọc thế nào
ttl trong thành viên là thời gian tươi còn lại lúc cache gửi header, làm tròn xuống giây. Ở ca 2, Edge còn 1 giây. Ở ca 3, OriginCache còn 1 giây. Crawler có thể dùng ttl để đoán lúc nào bản sẽ được làm mới, nhưng nhớ ttl của thành viên lịch sử là của thời điểm lưu, không phải bây giờ.
Ca 5, Accept-Language khác
Request với Accept-Language: en. Cả hai tầng có bản cho đường dẫn nhưng chỉ cho tiếng Việt. Origin nhận một request.
Cache-Status: OriginCache; fwd=vary-miss; stored; ttl=4, "Edge CDN"; fwd=vary-miss; stored; ttl=2
vary-miss cụ thể hơn uri-miss, đúng thứ tự RFC khuyến nghị.
Ca 6, no-cache từ client
Request có Cache-Control: no-cache. Bản tươi có sẵn nhưng chỉ thị của request không cho dùng. Origin nhận một request. Cả hai thành viên ghi fwd=request; stored.
no-cache có đi qua mọi tầng không
Ở ca 6, cả hai tầng ghi fwd=request, nghĩa là chỉ thị no-cache được chuyển tiếp lên trên. Nếu một tầng bỏ header này khi chuyển tiếp, tầng phía trên sẽ hit và trả bản cũ. Cache-Status cho thấy ngay chuyện đó: một thành viên hit đứng sau một thành viên fwd=request.
Ca 7, POST
Request POST. Cả hai tầng chuyển tiếp vì ngữ nghĩa method. Origin nhận một request. Thành viên ghi fwd=method; fwd-status=200, không stored.
Ca 8, có khóa cache
Request với X-Debug-Cache: 1. Edge hit, thêm key="/gia|vi". Thành viên của OriginCache là lịch sử từ ca 6, khi OriginCache lưu lại sau fwd=request.
Cache-Status: OriginCache; fwd=request; stored; ttl=4, "Edge CDN"; hit; ttl=2; key="/gia|vi"
Lịch sử có thể gây hiểu lầm
Ở ca 8, thành viên OriginCache ghi fwd=request từ ca 6, dù ca 8 không có no-cache. Người đọc không biết thứ tự này sẽ tưởng OriginCache vừa chuyển tiếp vì chỉ thị của request. Đây là ví dụ rõ nhất vì sao phải đọc từ cuối và dừng ở hit đầu tiên.
Ca 9, origin chết, URL mới
Lab tắt origin, gọi một đường dẫn chưa từng có. OriginCache không nối được origin, tự sinh 502, không thêm thành viên. Edge chuyển tiếp lên OriginCache, nhận 502, thêm thành viên.
Cache-Status: "Edge CDN"; fwd=uri-miss; fwd-status=502
=> phuc vu boi: upstream phia sau Edge CDN
Chỉ có một thành viên. OriginCache tuân quy tắc không gắn Cache-Status cho phản hồi tự tạo.
Ca 10, origin chết, có bản cũ
Lab gọi lại đường dẫn cũ khi bản của Edge đã hết hạn. Edge đi lên OriginCache. OriginCache có bản cũ, không nối được origin, trả bản cũ với ttl âm và detail=stale-if-error.
Cache-Status: OriginCache; hit; ttl=-1; detail=stale-if-error, "Edge CDN"; fwd=stale; stored; ttl=2
=> phuc vu boi: OriginCache
RFC nói bản cũ dùng mà không đi lên vì origin không sẵn sàng có thể coi là hit. ttl âm cho biết bản đã cũ bao lâu.
So RFC 9211 Cache-Status chẩn đoán với cf-cache-status để tránh dùng sai từ vựng chuẩn
Phần này gom bảng diễn giải và đối chiếu với Cloudflare.
Bảng diễn giải hop

Bảng hop phục vụ
Bảng dưới là đầu ra chính của bài, gom từ output thật của mười ca.
Ca |
Origin nhận |
OriginCache |
Edge CDN |
Hop phục vụ |
|---|---|---|---|---|
1 lần đầu |
1 |
fwd uri-miss, stored |
fwd uri-miss, stored |
origin |
2 ngay sau |
0 |
lịch sử |
hit ttl 1 |
Edge |
3 Edge cũ |
0 |
hit ttl 1 |
fwd stale, 304 |
Edge, OriginCache xác nhận |
4 cả hai cũ |
1 |
fwd stale, 304 |
fwd stale, stored |
OriginCache, origin xác nhận |
5 tiếng Anh |
1 |
fwd vary-miss |
fwd vary-miss |
origin |
6 no-cache |
1 |
fwd request |
fwd request |
origin |
7 POST |
1 |
fwd method |
fwd method |
origin |
8 debug |
0 |
lịch sử |
hit, có key |
Edge |
9 origin chết, mới |
0 |
không gắn |
fwd uri-miss, 502 |
OriginCache tự sinh 502 |
10 origin chết, cũ |
0 |
hit ttl âm |
fwd stale |
OriginCache |
Cột origin nhận là đếm thật phía origin, khớp với kết luận trong mọi ca.
Thành viên cuối nói ai trả lời lần này. Những thành viên trước nó chỉ kể lại lịch sử của bản lưu.
Client gộp dòng đúng
Edge gửi hai dòng Cache-Status riêng. httpx 0.28.1 get_list trả hai phần tử riêng, truy cập headers thường trả chuỗi đã gộp bằng dấu phẩy. requests 2.34.2 trả chuỗi đã gộp. Cả hai cách đều cho List đúng thứ tự khi parse.
httpx 0.28.1 get_list: ['OriginCache; hit; ttl=-3; detail=stale-if-error', '"Edge CDN"; fwd=stale; stored; ttl=2']
requests headers[...]: OriginCache; hit; ttl=-5; detail=stale-if-error, "Edge CDN"; fwd=stale; stored; ttl=2
ttl âm tăng dần qua các lần gọi vì bản lưu càng lúc càng cũ.
cf-cache-status là trường riêng
Tài liệu của Cloudflare liệt kê các giá trị của cf-cache-status như HIT, MISS, NONE/UNKNOWN, EXPIRED, STALE, BYPASS, REVALIDATED, UPDATING, DYNAMIC. Đây là một giá trị duy nhất cho một tầng, không phải danh sách nhiều hop, không có tham số.
Parse cf-cache-status như Cache-Status
Lab thử parse bốn giá trị HIT, MISS, DYNAMIC, EXPIRED bằng parser List của RFC 9211. Parser không lỗi, mỗi giá trị thành một thành viên có tên là chính giá trị đó, không có tham số hit hay fwd nào.
cf-cache-status: HIT -> parse nhu List RFC 9211: thanh vien 'HIT', params {} (khong co hit/fwd)
Hàm diagnose sẽ trả không xác định. Đó là kết quả đúng: cf-cache-status không mang ngữ nghĩa của RFC 9211.
Đừng ánh xạ một đối một
EXPIRED của Cloudflare gần với fwd=stale, REVALIDATED gần với fwd=stale; fwd-status=304, BYPASS gần với fwd=bypass. Nhưng định nghĩa chi tiết khác nhau. DYNAMIC chẳng hạn là nội dung Cloudflare không coi là cache được. Bảng ánh xạ, nếu cần, phải ghi rõ là ánh xạ gần đúng của riêng anh em.
cf-cache-status |
Gần với RFC 9211 |
Ghi chú |
|---|---|---|
HIT |
hit |
Một tầng Cloudflare |
MISS |
fwd=uri-miss hoặc miss |
Đủ điều kiện cache nhưng chưa có |
EXPIRED |
fwd=stale |
Bản đã hết hạn |
REVALIDATED |
fwd=stale, fwd-status=304 |
Xác thực lại với origin |
BYPASS |
fwd=bypass |
Cấu hình bỏ qua cache |
DYNAMIC |
không có tương đương |
Không đủ điều kiện cache theo Cloudflare |
Khi có cả hai trường
Phản hồi đi qua Cloudflare và một cache khác theo chuẩn có thể có cả cf-cache-status lẫn Cache-Status. Đọc riêng từng trường. Đừng chèn giá trị cf-cache-status vào danh sách Cache-Status khi phân tích, vì nó không có vị trí trong chuỗi hop.
Header riêng của các nhà cung cấp khác
Ngoài cf-cache-status, nhiều cache và CDN có header riêng như X-Cache với giá trị HIT hay MISS. Các header này thường chỉ cho một tầng, không có thứ tự hop, ý nghĩa tùy nhà cung cấp. Bộ đọc nên xử lý chúng ở nhánh riêng, với bảng giá trị lấy từ tài liệu của từng nhà cung cấp.
Đăng ký tham số mới
RFC 9211 tạo registry Cache-Status tại IANA. Tham số mới được thêm qua quy trình chuyên gia duyệt, ưu tiên tham số chung hơn tham số riêng của nhà cung cấp. Tham số lạ trong trường của anh em có thể là tham số đã đăng ký mà parser chưa biết, hoặc tham số riêng.
Đầu ra nghiệm thu của RFC 9211 Cache-Status chẩn đoán: chuỗi header và bảng hop phục vụ
Phần này gom tiêu chí và giới hạn.
Danh sách kiểm tra

cf-cache-status khác Cache-Status
Bộ đọc đạt khi mọi dòng dưới đây đúng.
- Parse bằng parser Structured Field, không tách chuỗi bằng tay.
- Đọc từ thành viên cuối ngược về đầu để tìm hop phục vụ.
- Coi thành viên phía trước một hit là lịch sử lưu, không phải đường đi lần này.
- Nhận ra fwd-status 304 là body từ bản lưu được xác nhận.
- Không có thành viên nào thì ghi không có dữ liệu, không đoán.
- Gộp nhiều dòng Cache-Status theo đúng thứ tự.
- Không đưa cf-cache-status vào cùng phân tích.
- Đối chiếu kết luận với log origin khi có thể.
Đối chiếu với log origin
Trong lab, cột origin nhận khớp với kết luận ở cả mười ca. Ở môi trường thật, log origin thường thuộc về bên khác. Khi có quyền, lấy log trong một khoảng thời gian ngắn và so với kết luận của bộ đọc trên vài chục request. Chỉ cần vài lệch là biết cache nào đang gắn Cache-Status không đúng chuẩn.
Dùng cho crawler
Crawler có thể ghi kết luận hop phục vụ cùng mỗi bản ghi. Bản ghi do cache phục vụ với ttl gần hết là bản có thể cũ. Khi cần dữ liệu mới nhất, gửi Cache-Control: no-cache, và kiểm Cache-Status có fwd=request ở mọi tầng như ca 6. Tầng nào vẫn hit là tầng không tôn trọng chỉ thị.
Ghi kết luận cùng bản ghi
Mỗi bản ghi crawl nên có cột hop phục vụ và cột ttl của thành viên phục vụ. Khi phân tích dữ liệu cũ, hai cột này giúp tách bản lấy từ origin với bản lấy từ cache. Nếu nguồn không gửi Cache-Status, ghi rõ không có dữ liệu, đừng để trống làm người đọc tưởng là origin.
Những gì lab chưa chạy
Chưa thử CDN hay cache thật gửi Cache-Status. Chưa thử collapsed, partial, bypass. Chưa thử cache của trình duyệt tự thêm thành viên. Chưa thử HTTP/2. Quy tắc cache và quy ước X-Debug-Cache là của lab. Bảng ánh xạ cf-cache-status là ánh xạ gần đúng, không phải quy định.
Chạy lại với cache thật
Gửi vài request liên tiếp tới cùng URL qua cache của anh em, đọc Cache-Status mỗi lần. Thấy hit ở thành viên cuối sau request đầu là cache đang hoạt động. Không thấy trường nào là cache không gửi Cache-Status, hoặc đã tắt. Varnish, Nginx và các proxy khác có cấu hình riêng, bài Varnish cache proxy có ví dụ về một cache cụ thể.
Proxy ở đâu trong luồng
Proxy IP dùng cho crawler thường không cache, nên không thêm thành viên. Cache nằm ở phía website, như CDN và reverse proxy. Khi cần IP tại Việt Nam để thấy đúng cache của vùng, anh em có thể mua proxy tại trang chủ ProxyVN. CDN có thể có bản lưu khác nhau theo vùng, Cache-Status giúp thấy điều đó. Khái niệm cache ở proxy có trong bài proxy caching là gì, vai trò proxy trong crawler có ở bài Web Scraping proxy là gì, cách ghi chuỗi cấu hình ở bài định dạng proxy.
RFC 9211 Cache-Status chẩn đoán: câu hỏi thường gặp
Các câu dưới đây gom những điểm hay bị hỏi.
Thành viên đầu tiên là tầng nào?
Tầng gần origin nhất. Thành viên cuối là tầng gần client nhất.
Có fwd ở thành viên đầu nghĩa là request đã tới origin?
Không nhất thiết. Nếu thành viên cuối hit, thành viên đầu là lịch sử lưu. Lab có ca 2 và ca 8 như vậy.
fwd=stale; fwd-status=304 nghĩa là gì?
Tầng đó có bản cũ, đi lên xác thực, nhận 304, rồi trả body đã lưu. Body không đến từ phía trên.
Vì sao cache tự sinh 502 không có Cache-Status?
RFC 9211 nói intermediary không nên thêm thành viên cho phản hồi tự tạo. Lab có ca 9 đúng như vậy.
cf-cache-status có phải Cache-Status không?
Không. Đó là trường riêng của Cloudflare, một giá trị cho một tầng, không có tham số.
Có nên gửi key cho mọi client?
Không. RFC cảnh báo key có thể giúp đầu độc cache. Lab chỉ gửi key khi bật debug.
Proxy IP có thêm Cache-Status không?
Proxy chuyển tiếp không cache thì không thêm. Trường anh em thấy thường đến từ CDN và reverse proxy phía website.
RFC 9211 Cache-Status chẩn đoán và những điều cần nhớ
RFC 9211 Cache-Status chẩn đoán đúng khi parse bằng Structured Field, đọc từ thành viên cuối, hiểu thành viên phía trước một hit là lịch sử, và không lẫn với cf-cache-status. Luôn đối chiếu với log origin khi có. Proxy.vn - Nhà cung cấp dịch vụ proxy chất lượng hàng đầu Việt Nam khuyên anh em giữ bảng hop phục vụ cho RFC 9211 Cache-Status chẩn đoán.