Header Cache-Control HTTP Dijelaskan di Situs Next.js Nyata
Pelajari header Cache-Control HTTP dari next.config.ts nyata: max-age, immutable, no-cache vs no-store, ETag dan 304, serta cara Cloudflare membacanya.
Oleh Matthews WongDitinjau pada
Poin utama
Cache-Control adalah header response yang memberi tahu browser dan CDN berapa lama mereka boleh memakai ulang sebuah response tanpa bertanya lagi ke server. max-age menentukan masa segar, no-cache mewajibkan validasi sebelum dipakai ulang, no-store melarang penyimpanan, dan immutable berjanji file tidak akan berubah. Masa lama baru aman jika URL ikut berubah saat isinya berubah.
Setelah pelajaran ini, Anda bisa
- Membaca header Cache-Control dan menjelaskan janji max-age, s-maxage, no-cache, no-store, dan immutable.
- Menjelaskan kenapa masa simpan satu tahun aman untuk file ber-hash dan salah untuk nama yang tidak pernah berubah.
- Memperkirakan apa yang di-cache Cloudflare dari header response, dan membaca cf-cache-status untuk memeriksanya.
Ikuti diagramnya langkah demi langkah
Tekan Putar, atau melangkah dengan panah. Setiap langkah juga ditulis di bawah diagram.
Cara satu header menentukan siapa yang menjawab
Browser meminta ke edge CDN, yang meminta ke origin. File ber-hash dengan header immutable satu tahun dijawab dari cache sejak itu; file yang bisa berubah dengan nama tetap harus divalidasi.
Tombol: ← → langkah · Home / End · K putar atau jeda
Tiga tempat bisa menyimpan salinan: cache milik browser, edge CDN, dan aplikasinya sendiri. Cache-Control pada response memberi tahu dua yang pertama berapa lama menyimpannya.
Request pertama menempuh seluruh jalur sampai ke aplikasi. File ber-hash kembali dengan header immutable satu tahun, dan edge melaporkan MISS.
Cache-Control: public, max-age=31536000, immutableEdge menyimpan file karena headernya public dengan max-age di atas nol. Browser juga menyimpannya, dan selama masih segar kunjungan ulang tidak mengirim request sama sekali.
Tebak langkah berikutnya Pengunjung lain sekarang meminta file ber-hash yang sama. Siapa yang menjawab? (Aplikasi, setiap kali · Edge CDN, dari cache-nya · Tidak ada: request gagal)Edge menjawab dari salinannya dan melaporkan cf-cache-status HIT. Request tidak pernah sampai ke aplikasi, jadi origin tidak bekerja lagi untuk file ini.
Deploy baru menghasilkan hash baru, jadi URL baru. URL lama tetap ter-cache dan tidak berbahaya, dan tidak ada yang perlu di-purge agar perubahan terlihat.
Tebak langkah berikutnya Sebuah file tetap bernama sama tetapi isinya berubah, dan salinan cache-nya sudah basi. Apa yang dilakukan cache berikutnya? (Menyajikan salinan lama selamanya · Bertanya ke origin dengan conditional request · Menghapusnya tanpa bertanya)Nama yang tidak pernah boleh berubah tidak bisa membawa janji setahun. Salinan basi divalidasi ulang: cache mengirim ETag-nya, dan aplikasi menjawab 304 Not Modified jika tidak ada perubahan.
If-None-Match: the saved ETag 304 Not Modified
Apa yang diperintahkan Cache-Control kepada cache?
Cache-Control adalah header response yang memberi tahu setiap cache di antara server dan layar berapa lama sebuah response boleh dipakai ulang. max-age=N berarti response tetap segar sampai N detik setelah dibuat. s-maxage menyatakan hal yang sama khusus untuk shared cache seperti CDN, dan menimpa max-age di sana. Cache browser bersifat privat untuk satu klien, sedangkan CDN atau reverse proxy dipakai bersama oleh banyak klien.
Baca selengkapnya (2)Tutup
Dua directive sering tertukar. no-cache tidak berarti jangan di-cache: response boleh disimpan, tetapi harus divalidasi ke origin sebelum setiap pemakaian ulang. no-store adalah yang berarti jangan disimpan, di cache mana pun. public mengizinkan shared cache menyimpan response, dan immutable menyatakan response tidak akan diperbarui selama masih segar.
Tanpa Cache-Control sama sekali, cache tetap boleh menyimpan response dan memakainya ulang selama waktu yang mereka tentukan sendiri. Itu disebut heuristic caching, dan saran MDN adalah hampir semua response sebaiknya menyebutkan Cache-Control secara eksplisit, supaya perilakunya menjadi keputusan, bukan tebakan.
Kenapa masa simpan setahun aman untuk sebagian URL dan salah untuk yang lain?
Masa simpan panjang hanya aman jika isi di balik sebuah URL tidak pernah berubah. Pola cache busting membuatnya benar: taruh versi atau hash konten di URL, jangan pernah mengubah file-nya, lalu kirim Cache-Control: public, max-age=31536000, immutable. Versi baru mendapat URL baru, jadi tidak ada cache yang menyimpan isi yang salah untuk sebuah nama. 31536000 detik sama dengan satu tahun.
Baca selengkapnya (2)Tutup
Next.js menerapkan pola ini sendiri: ia memasang header persis seperti itu pada aset yang benar-benar immutable dan bernama hash, dan dokumentasinya menyebut Anda tidak bisa menimpanya dari next.config. Situs ini mengirim header yang sama untuk /images/*, file gambar di root, dan, khusus di production, untuk /_next/static/*. Syarat khusus production itu disengaja: chunk saat development memakai nama yang sama di setiap edit, jadi cache setahun di sana membuat browser menjalankan kode basi.
Sisa next.config.ts menunjukkan cara memperlakukan nama yang tidak bisa berubah. Film hanya immutable jika URL-nya membawa stempel render ?v=. File game ber-hash konten, tetapi manifest.json miliknya, yang namanya tidak pernah berubah, dikecualikan dari aturan itu. HTML tidak bisa di-cache-bust sama sekali, itulah sebabnya MDN merekomendasikan no-cache untuknya: boleh disimpan, tetapi tanyakan dulu ke origin.
Bagaimana Cloudflare bertindak berdasarkan header ini?
Cloudflare menentukan apa yang layak di-cache berdasarkan ekstensi file, bukan MIME type, dan tidak meng-cache HTML atau JSON secara default. Untuk file yang layak, ia mengikuti origin: response yang public dengan max-age di atas nol akan di-cache, sedangkan private, no-store, no-cache, atau max-age=0 membuatnya tidak di-cache. Response yang menyetel cookie tidak di-cache, dan hanya request GET yang di-cache.
Baca selengkapnya (2)Tutup
Keputusannya bisa dibaca di header response cf-cache-status. HIT berarti file datang dari cache Cloudflare. MISS berarti file layak di-cache tetapi belum tersimpan, jadi origin yang menjawab. DYNAMIC berarti file dinilai tidak layak, sehingga tidak ada pencarian di cache. EXPIRED, REVALIDATED, BYPASS, dan STALE mencakup kasus lainnya. Periksa URL mana pun dengan curl -sI.
Dua fakta lagi berguna saat Anda mengubah aturan. Di Next.js, jika dua aturan header cocok dengan satu path dan menyetel key yang sama, aturan yang terakhir menang. Dan jika file yang ter-cache harus hilang sebelum kedaluwarsa, Cloudflare menyediakan beberapa metode purge, dengan purge per URL sebagai yang direkomendasikan. URL baru sama sekali tidak butuh purge, itulah inti bagian sebelumnya.
Apa yang terjadi saat salinan di cache menjadi basi?
Basi tidak berarti dihapus. Cache bisa memvalidasi ulang dengan conditional request: ia mengirim validator yang tersimpan, biasanya ETag, dalam header If-None-Match. Jika tidak ada perubahan, server menjawab 304 Not Modified tanpa body dan cache menandai salinannya segar kembali. Jika berubah, server mengembalikan 200 dengan body baru.
Baca selengkapnya (1)Tutup
Itu sebabnya no-cache cocok untuk file bernama tetap seperti HTML: kasus yang umum hanya butuh satu round trip kecil, bukan unduhan penuh. immutable menghapus bahkan request itu saat pengunjung me-reload, yang menurut MDN tidak perlu untuk file yang tidak pernah diubah, tetapi hanya jujur jika nama itu tidak pernah dipakai ulang.
Konfigurasi nyata di balik pelajaran ini
Kutipan dari repositori yang membangun dan men-deploy situs ini, apa adanya.
// Production only. Build chunks are content-hashed there, so a year of
// immutable caching is safe. Turbopack's dev chunks keep the same name
// across edits, and this header in development made browsers keep
// running stale game code for as long as their cache lived — the
// "sometimes WASD stops working" reports were a mix of old and new
// modules, not the controller.
...(process.env.NODE_ENV === "production"
? [
{
source: "/_next/static/(.*)",
headers: [
{
key: "Cache-Control",
value: "public, max-age=31536000, immutable",
}, // Cache static assets for 1 year
],
},
]
: []),Aturan satu tahun untuk chunk hasil build, di balik pengecekan production. Komentarnya adalah pelajarannya: header ini aman hanya karena chunk production ber-hash konten, dan header yang sama saat development pernah membuat browser menjalankan kode game yang basi. Aturan serupa untuk gambar, di baris 157-177, tidak punya syarat itu karena URL-nya disajikan apa adanya.
{
// The films, their posters and captions. A re-render keeps the file
// names, so only a request carrying the render stamp
// (lib/film-manifest.ts prints `?v=` on every URL) may be cached as
// immutable; Cloudflare then serves the films from its edge. A bare
// URL, from an old link, keeps revalidating against the origin.
source: "/videos/:path*",
has: [{ type: "query", key: "v" }],
headers: [
{
key: "Cache-Control",
value: "public, max-age=31536000, immutable",
},
],
},Nama yang tidak berubah, ditangani dengan syarat. has hanya cocok untuk request yang membawa query parameter v, jadi film hasil render ulang bersifat immutable di bawah URL bercap, sedangkan URL polos dari tautan lama tetap divalidasi ulang. Komentarnya menyebut Cloudflare lalu melayani film ini dari edge-nya.
{
// The Archipelago's models, textures and decoders (prd.md §7). Files
// are content-hashed by scripts/game/build-manifest.mjs, so they can
// be immutable; Cloudflare then serves every repeat from the edge and
// the 1 vCPU origin never streams a model twice. The manifest itself
// is excluded: it is the one file whose name never changes.
source: "/game/:path((?!manifest\\.json$).*)",
headers: [
{
key: "Cache-Control",
value: "public, max-age=31536000, immutable",
},
],
},Gagasan yang sama lewat pengecualian. Negative lookahead pada pola path mencocokkan semua yang ada di bawah /game/ kecuali manifest.json. Semua file lain ber-hash konten, jadi boleh immutable; manifest adalah satu-satunya file yang namanya tidak pernah berubah, jadi aturan ini tidak memberinya janji setahun.
Kesalahan yang benar-benar membuang waktu
immutable pada nama yang dipakai ulang
Header immutable setahun pada nama yang isinya berubah meninggalkan salinan lama di setiap browser yang pernah mengambilnya. Purge di CDN tidak menjangkau salinan yang sudah tersimpan di browser, karena cache browser bersifat privat untuk tiap klien. Ubah URL-nya, atau jangan beri janji panjang itu.
Cache panjang saat development
Chunk development Turbopack memakai nama yang sama di setiap edit. Situs ini pernah mengirim header immutable juga saat development, dan browser menjalankan campuran modul game lama dan baru. Perbaikannya adalah pengecekan production di next.config.ts. Periksa header yang benar-benar dikirim, bukan yang dimaksudkan.
no-cache dibaca sebagai jangan di-cache
no-cache mengizinkan penyimpanan dan hanya menuntut validasi sebelum dipakai ulang. Halaman berisi data pribadi yang tidak boleh disimpan di mana pun butuh no-store, dan response yang dipersonalisasi juga butuh private agar shared cache melewatinya. Membaca namanya secara harfiah adalah cara halaman privat berakhir tersimpan.
File yang layak di-cache tetapi tidak pernah di-cache
Cache-Control yang sempurna diabaikan jika Cloudflare melihat Set-Cookie pada response, request non-GET, atau ekstensi file di luar daftar defaultnya. Jika cf-cache-status menunjukkan DYNAMIC untuk gambar atau script, periksa hal-hal itu sebelum header-nya.
| Directive | Boleh disimpan | Dipakai tanpa bertanya |
|---|---|---|
| max-age=N | Ya | Selama N detik |
| s-maxage=N | Di shared cache | Selama N detik, menimpa max-age di sana |
| no-cache | Ya | Tidak pernah: validasi dulu |
| no-store | Tidak | Tidak berlaku |
| immutable | Ya, bersama max-age | Selama segar, termasuk saat reload |
Lakukan di komputer Anda sendiri
Anda butuh curl dan Node. Pertama baca header live situs ini, lalu buat server kecil yang menjawab 304.
Baca header yang dibawa sebuah halaman HTML. Catat apakah Cache-Control dan cf-cache-status ada, dan apa isinya.
curl -sI https://www.matthewswong.com/en/ | grep -i -E "cache-control|cf-cache-status"Cari satu chunk ber-hash yang dimuat halaman, lalu minta dua kali. Bandingkan dua nilai cf-cache-status dan baris Cache-Control dengan aturan di next.config.ts.
CHUNK=$(curl -s https://www.matthewswong.com/en/ | grep -o "/_next/static/[^\"]*\.js" | head -1) curl -sI "https://www.matthewswong.com$CHUNK" | grep -i -E "cache-control|cf-cache-status" curl -sI "https://www.matthewswong.com$CHUNK" | grep -i -E "cache-control|cf-cache-status"Tulis server yang mengirim ETag dan menjawab 304 saat ETag yang sama dikirim kembali.
// server.mjs import { createServer } from "node:http"; const ETAG = '"v1"'; createServer((req, res) => { if (req.headers["if-none-match"] === ETAG) { res.writeHead(304, { ETag: ETAG }); return res.end(); } res.writeHead(200, { ETag: ETAG, "Cache-Control": "no-cache" }); res.end("hello\n"); }).listen(3000);Jalankan, lalu minta secara biasa dan sekali lagi dengan validator. Panggilan kedua seharusnya menampilkan 304 tanpa body.
node server.mjs & curl -i http://localhost:3000 curl -i -H 'If-None-Match: "v1"' http://localhost:3000 kill %1
Tiga pertanyaan sebelum lanjut
Pilih jawaban untuk melihat kenapa benar atau salah. Tidak ada yang disimpan atau dinilai, jadi tebak saja dengan bebas.
Jawab dalam hati, lalu cek
1.Sebuah file ber-hash berubah di deploy baru. Apa yang harus dilakukan pada entri cache-nya?Lihat jawabannya
Jawaban:Tidak ada. Isi baru punya hash baru, jadi URL baru, dan salinan cache dari URL lama tidak pernah diminta lagi. Itulah pola cache busting: ubah URL, bukan purge.
2.Kenapa manifest.json milik game dikecualikan dari aturan immutable padahal semua file game lain termasuk?Lihat jawabannya
Jawaban:Namanya tidak pernah berubah. Janji setahun hanya bekerja jika isi baru mendapat nama baru, jadi satu-satunya file bernama tetap itu harus boleh divalidasi ulang.
3.Sebutkan tiga hal yang membuat Cloudflare tidak meng-cache file yang sebenarnya layak.Lihat jawabannya
Jawaban:Cache-Control berisi private, no-store, no-cache, atau max-age=0; header Set-Cookie pada response; dan request yang bukan GET. HTML dan JSON juga tidak di-cache secara default.
Bahasan mendalam terkait di situs ini
Sumber
Sumber primer yang diperiksa pada tanggal riset. Ikuti tautannya untuk versi terbaru.