Langsung ke konten utama

[Medium] πŸ“„ HTTP Caching

1. Apa itu HTTP caching dan mengapa penting?​

Apa itu HTTP caching? Mengapa penting?

HTTP caching adalah teknik yang menyimpan respons HTTP sementara di klien (browser) atau server perantara, sehingga permintaan selanjutnya bisa menggunakan ulang data yang di-cache tanpa harus mengakses server asal lagi.

Cache vs Penyimpanan Sementara (Temporary Storage)​

Dalam konteks teknis, kedua istilah ini sering tercampur, tapi keduanya memiliki tujuan yang berbeda.

Cache​

Definisi: salinan tersimpan yang digunakan untuk optimisasi performa, fokus pada penggunaan ulang dan akses yang lebih cepat.

Karakteristik:

  • βœ… Tujuan: peningkatan performa
  • βœ… Data diharapkan untuk digunakan ulang
  • βœ… Strategi kedaluwarsa/revalidasi yang eksplisit
  • βœ… Biasanya salinan dari data asli

Contoh:

// HTTP Cache - cache respons API
Cache-Control: max-age=3600 // cache 1 jam

// Memory Cache - cache hasil komputasi
const cache = new Map();
function fibonacci(n) {
if (cache.has(n)) return cache.get(n); // gunakan ulang cache
const result = /* hitung */;
cache.set(n, result);
return result;
}

Penyimpanan Sementara (Temporary Storage)​

Definisi: data yang disimpan untuk kebutuhan alur kerja sementara, menekankan siklus hidup yang singkat.

Karakteristik:

  • βœ… Tujuan: penyimpanan sementara
  • βœ… Penggunaan ulang opsional
  • βœ… Biasanya siklus hidup lebih pendek
  • βœ… Mungkin menyimpan state perantara

Contoh:

// sessionStorage - data formulir sementara
sessionStorage.setItem('formData', JSON.stringify(form));

// path file upload sementara
const tempFile = await uploadToTemp(file);
await processFile(tempFile);
await deleteTempFile(tempFile);

Perbandingan​

FiturCachePenyimpanan Sementara
Tujuan utamaPerformaPenyimpanan sementara
Penggunaan ulangYa, sering berulangTidak dijamin
Siklus hidupDigerakkan kebijakanBiasanya pendek
Penggunaan umumHTTP cache, memory cachesessionStorage, file temp
Istilah InggrisCacheTemp / Temporary / Buffer

Perbedaan praktis​

// ===== Skenario cache =====

// 1) HTTP cache: gunakan ulang respons API
fetch('/api/users').then((response) => response.json());
fetch('/api/users').then((response) => response.json());

// 2) memoization cache
const memoize = (fn) => {
const cache = new Map();
return (...args) => {
const key = JSON.stringify(args);
if (cache.has(key)) return cache.get(key);
const result = fn(...args);
cache.set(key, result);
return result;
};
};

// ===== Skenario penyimpanan sementara =====

// 1) simpan draf saat unload
window.addEventListener('beforeunload', () => {
sessionStorage.setItem('formDraft', JSON.stringify(formData));
});

// 2) pemrosesan upload sementara
async function handleUpload(file) {
const tempPath = await uploadToTempStorage(file);
const processed = await processFile(tempPath);
await deleteTempFile(tempPath);
return processed;
}

// 3) hasil perantara sementara
const tempResults = [];
for (const item of items) {
tempResults.push(process(item));
}
const final = combine(tempResults);

Dalam pengembangan web​

// HTTP Cache (berumur panjang, bisa digunakan ulang)
Cache-Control: public, max-age=31536000, immutable

// sessionStorage (sementara, cakupan per tab)
sessionStorage.setItem('tempData', data)

// localStorage (penyimpanan persisten, bukan lapisan optimisasi cache utama)
localStorage.setItem('userPreferences', prefs)

Mengapa perbedaan ini penting​

  1. Keputusan desain:
    • Butuh optimisasi performa -> cache
    • Butuh penyimpanan sementara -> temp storage
  2. Manajemen sumber daya:
    • Cache fokus pada hit rate dan strategi kedaluwarsa
    • Temp storage fokus pada waktu pembersihan dan batas ukuran
  3. Kejelasan wawancara:
    • Pertanyaan performa -> bahas strategi caching
    • Pertanyaan data sementara -> bahas strategi temp storage

Artikel ini terutama fokus pada cache, khususnya HTTP caching.

Manfaat caching​

  1. Lebih sedikit permintaan jaringan
  2. Beban server lebih rendah
  3. Pemuatan halaman lebih cepat
  4. Penggunaan bandwidth lebih rendah
  5. Pengalaman pengguna lebih baik

Lapisan cache browser​

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚ Lapisan Cache Browser β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚ 1. Memory Cache β”‚
β”‚ - Tercepat, kapasitas kecil β”‚
β”‚ - Dibersihkan saat tab/sesi β”‚
β”‚ berakhir β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚ 2. Disk Cache β”‚
β”‚ - Lebih lambat, kapasitas besar β”‚
β”‚ - Penyimpanan persisten β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚ 3. Service Worker Cache β”‚
β”‚ - Dikontrol penuh oleh aplikasi β”‚
β”‚ - Memungkinkan perilaku offline β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

2. Apa saja strategi HTTP caching?​

Strategi caching apa yang ada di HTTP?

Kategori strategi​

Strategi HTTP Caching
β”œβ”€β”€ Strong Cache (Segar)
β”‚ β”œβ”€β”€ Cache-Control
β”‚ └── Expires
└── Validation Cache (Negosiasi)
β”œβ”€β”€ Last-Modified / If-Modified-Since
└── ETag / If-None-Match

1. Strong cache (cache segar)​

Perilaku: browser menyajikan dari cache lokal secara langsung tanpa mengirim permintaan ke server asal.

Cache-Control (HTTP/1.1)​

Cache-Control: max-age=3600

Directive umum:

// 1) max-age: masa berlaku kesegaran dalam detik
Cache-Control: max-age=3600

// 2) no-cache: izinkan caching tapi wajibkan revalidasi sebelum penggunaan ulang
Cache-Control: no-cache

// 3) no-store: jangan cache sama sekali
Cache-Control: no-store

// 4) public: bisa di-cache oleh browser/CDN/proxy
Cache-Control: public, max-age=31536000

// 5) private: hanya cache browser
Cache-Control: private, max-age=3600

// 6) immutable: konten tidak akan berubah selama masa kesegaran
Cache-Control: public, max-age=31536000, immutable

// 7) must-revalidate: setelah kedaluwarsa, harus revalidasi
Cache-Control: max-age=3600, must-revalidate

Expires (HTTP/1.0, legacy)​

Expires: Wed, 21 Oct 2025 07:28:00 GMT

Masalah:

  • Menggunakan waktu absolut
  • Bergantung pada kebenaran jam klien
  • Sebagian besar digantikan oleh Cache-Control

2. Validation cache (negosiasi)​

Perilaku: browser bertanya ke server apakah sumber daya berubah.

Last-Modified / If-Modified-Since​

# respons pertama
Last-Modified: Wed, 21 Oct 2024 07:28:00 GMT

# permintaan selanjutnya
If-Modified-Since: Wed, 21 Oct 2024 07:28:00 GMT

Alur:

  1. Permintaan pertama: server mengirim Last-Modified
  2. Permintaan berikutnya: browser mengirim If-Modified-Since
  3. Tidak berubah: server mengembalikan 304 Not Modified
  4. Berubah: server mengembalikan 200 OK + body baru

ETag / If-None-Match​

# respons pertama
ETag: "33a64df551425fcc55e4d42a148795d9f25f89d4"

# permintaan selanjutnya
If-None-Match: "33a64df551425fcc55e4d42a148795d9f25f89d4"

Keunggulan:

  • Lebih presisi dari Last-Modified
  • Berbasis konten (hash atau token versi)
  • Bisa mendeteksi perubahan yang tidak terlihat di timestamp level detik

Last-Modified vs ETag​

FiturLast-ModifiedETag
PresisiLevel detikToken/hash konten, lebih presisi
BiayaLebih rendahMungkin perlu komputasi ekstra
Cocok untukFile statis umumKontrol validasi yang tepat
PrioritasLebih rendahLebih tinggi (ETag diutamakan saat keduanya ada)

3. Bagaimana cara kerja caching browser?​

Apa alur kerja cache browser?

Alur kerja lengkap​

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚ Alur Permintaan Sumber Daya Browser β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
↓
1. Periksa Memory Cache
↓
β”Œβ”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚ Hit cache? β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”˜
Ya β”‚ Tidak
↓
2. Periksa Disk Cache
↓
β”Œβ”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚ Hit cache? β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”˜
Ya β”‚ Tidak
↓
3. Periksa Service Worker
↓
β”Œβ”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚ Hit cache? β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”˜
Ya β”‚ Tidak
↓
4. Periksa kesegaran
↓
β”Œβ”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚ Kedaluwarsa? β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”˜
Ya β”‚ Tidak
↓
5. Revalidasi dengan server
↓
β”Œβ”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚ Berubah? β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”˜
Ya β”‚ Tidak (304)
↓
6. Minta konten baru
↓
β”Œβ”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚ Kembalikan β”‚
β”‚ 200 + body β”‚
β”‚ baru β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

Contoh praktis​

// permintaan pertama
GET /api/data.json
Response:
200 OK
Cache-Control: max-age=3600
ETag: "abc123"

{ data: "..." }

// dalam 1 jam
// strong cache hit -> gunakan lokal, tidak ada permintaan
// status yang ditampilkan devtools: from disk cache atau from memory cache

// setelah 1 jam
GET /api/data.json
If-None-Match: "abc123"

// tidak berubah
Response:
304 Not Modified

// berubah
Response:
200 OK
ETag: "def456"

{ data: "data baru" }

4. Apa saja strategi caching yang umum?​

Strategi caching praktis yang umum

1. Aset statis berumur panjang​

// HTML: jangan cache lama, selalu validasi
Cache-Control: no-cache

// CSS/JS dengan hash: cache immutable yang lama
Cache-Control: public, max-age=31536000, immutable
// nama file: main.abc123.js

Prinsip:

  • HTML harus tetap segar untuk mereferensikan hash aset terbaru
  • Aset statis yang di-hash bisa di-cache untuk waktu lama
  • Perubahan konten -> perubahan nama file -> unduhan baru

2. Sumber daya yang sering diperbarui​

// Data API: cache pendek + revalidasi
Cache-Control: max-age=60, must-revalidate
ETag: "abc123"

3. Strategi gambar​

// avatar pengguna: cache menengah
Cache-Control: public, max-age=86400

// logo/ikon: cache lebih lama
Cache-Control: public, max-age=2592000

// gambar dinamis: validasi
Cache-Control: no-cache
ETag: "image-hash"

4. Kebijakan yang disarankan berdasarkan jenis sumber daya​

const cachingStrategies = {
html: 'Cache-Control: no-cache',
staticWithHash: 'Cache-Control: public, max-age=31536000, immutable',
staticAssets: 'Cache-Control: public, max-age=2592000',
apiData: 'Cache-Control: private, max-age=60',
userData: 'Cache-Control: private, no-cache',
sensitive: 'Cache-Control: no-store',
};

5. Service Worker caching​

Service Worker caching

Service Worker memberikan kontrol penuh atas runtime caching dan perilaku offline.

Penggunaan dasar​

// daftarkan Service Worker
if ('serviceWorker' in navigator) {
navigator.serviceWorker.register('/sw.js');
}
// sw.js
const CACHE_NAME = 'my-app-v1';
const urlsToCache = [
'/',
'/styles/main.css',
'/scripts/main.js',
'/images/logo.png',
];

// install: pre-cache aset statis
self.addEventListener('install', (event) => {
event.waitUntil(
caches.open(CACHE_NAME).then((cache) => {
return cache.addAll(urlsToCache);
})
);
});

// fetch: contoh cache-first
self.addEventListener('fetch', (event) => {
event.respondWith(
caches.match(event.request).then((response) => {
return response || fetch(event.request);
})
);
});

// activate: bersihkan cache lama
self.addEventListener('activate', (event) => {
event.waitUntil(
caches.keys().then((cacheNames) => {
return Promise.all(
cacheNames.map((cacheName) => {
if (cacheName !== CACHE_NAME) {
return caches.delete(cacheName);
}
})
);
})
);
});

Strategi SW yang umum​

1. Cache First​

// terbaik untuk aset statis
self.addEventListener('fetch', (event) => {
event.respondWith(
caches.match(event.request).then((response) => {
return response || fetch(event.request);
})
);
});

2. Network First​

// terbaik untuk permintaan API
self.addEventListener('fetch', (event) => {
event.respondWith(
fetch(event.request)
.then((response) => {
const responseClone = response.clone();
caches.open(CACHE_NAME).then((cache) => {
cache.put(event.request, responseClone);
});
return response;
})
.catch(() => {
return caches.match(event.request);
})
);
});

3. Stale While Revalidate​

// terbaik untuk respons cepat + pembaruan di background
self.addEventListener('fetch', (event) => {
event.respondWith(
caches.match(event.request).then((cachedResponse) => {
const fetchPromise = fetch(event.request).then((networkResponse) => {
caches.open(CACHE_NAME).then((cache) => {
cache.put(event.request, networkResponse.clone());
});
return networkResponse;
});

return cachedResponse || fetchPromise;
})
);
});

6. Bagaimana cara mengimplementasikan cache busting?​

Bagaimana cara mengimplementasikan cache busting?

Cache busting memastikan pengguna mengambil aset terbaru saat konten berubah.

Metode 1: hashing nama file (direkomendasikan)​

// dengan Webpack/Vite
// output: main.abc123.js

// webpack.config.js
module.exports = {
output: {
filename: '[name].[contenthash].js',
},
};
<script src="/js/main.abc123.js"></script>

Kelebihan:

  • βœ… Nama file baru memaksa unduhan
  • βœ… File lama tetap bisa di-cache
  • βœ… Best practice industri

Metode 2: query versi​

<script src="/js/main.js?v=1.2.3"></script>
<link rel="stylesheet" href="/css/style.css?v=1.2.3" />

Kekurangan:

  • ❌ Beberapa CDN/proxy memperlakukan caching query-string secara berbeda
  • ❌ Pemeliharaan versi manual

Metode 3: timestamp​

// umum hanya di development
const timestamp = Date.now();
const script = document.createElement('script');
script.src = `/js/main.js?t=${timestamp}`;
document.body.appendChild(script);

Kasus penggunaan:

  • bypass cache di development
  • tidak ideal untuk production

7. Pertanyaan wawancara caching yang umum​

Pertanyaan wawancara caching yang umum

Pertanyaan 1: Bagaimana cara mencegah HTML di-cache?​

Klik untuk melihat jawaban
Cache-Control: no-cache, no-store, must-revalidate
Pragma: no-cache
Expires: 0

atau tag meta HTML:

<meta
http-equiv="Cache-Control"
content="no-cache, no-store, must-revalidate"
/>
<meta http-equiv="Pragma" content="no-cache" />
<meta http-equiv="Expires" content="0" />

Pertanyaan 2: Mengapa menggunakan ETag dan bukan hanya Last-Modified?​

Klik untuk melihat jawaban

Keunggulan ETag:

  1. Lebih presisi
  2. Validasi berbasis konten
  3. Menghindari kasus edge timestamp (re-deploy dengan konten yang sama)
  4. Lebih baik di sistem terdistribusi dengan jam yang tidak sinkron

Contoh:

// konten tidak berubah, waktu deployment berubah
// Last-Modified berubah, tapi konten identik

ETag: 'hash-of-abc'; // stabil jika konten tidak berubah

Pertanyaan 3: perbedaan antara from disk cache dan from memory cache?​

Klik untuk melihat jawaban
FiturMemory CacheDisk Cache
PenyimpananRAMDisk
KecepatanSangat cepatLebih lambat
KapasitasLebih kecilLebih besar
PersistensiBiasanya berumur pendekPersisten
PrioritasLebih tinggiLebih rendah

Urutan pemuatan umum (konseptual):

1. Memory Cache
2. Service Worker Cache
3. Disk Cache
4. Revalidasi / Jaringan

Pertanyaan 4: bagaimana cara memaksa browser memuat ulang sumber daya?​

Klik untuk melihat jawaban

Development:

// Hard Reload
// Nonaktifkan cache di DevTools

const script = document.createElement('script');
script.src = `/js/main.js?t=${Date.now()}`;

Production:

// nama file dengan hash (terbaik)
main.abc123.js

// query versi
<script src="/js/main.js?v=2.0.0"></script>

// kebijakan cache
Cache-Control: no-cache
Cache-Control: no-store

Pertanyaan 5: bagaimana cara mengimplementasikan cache offline di PWA?​

Klik untuk melihat jawaban
// sw.js
const CACHE_NAME = 'pwa-v1';
const OFFLINE_URL = '/offline.html';

self.addEventListener('install', (event) => {
event.waitUntil(
caches.open(CACHE_NAME).then((cache) => {
return cache.addAll([
OFFLINE_URL,
'/styles/offline.css',
'/images/offline-icon.png',
]);
})
);
});

self.addEventListener('fetch', (event) => {
if (event.request.mode === 'navigate') {
event.respondWith(
fetch(event.request).catch(() => {
return caches.match(OFFLINE_URL);
})
);
}
});

Strategi PWA lengkap biasanya menggabungkan:

// 1) aset statis: cache-first
// 2) API: network-first
// 3) gambar: cache-first
// 4) navigasi HTML: network-first + fallback offline

8. Best practice​

Best practice

βœ… Direkomendasikan​

// 1. HTML: jangan cache lama untuk memastikan dokumen entry terbaru
Cache-Control: no-cache

// 2. CSS/JS dengan hash: cache immutable yang lama
// contoh nama file: main.abc123.js
Cache-Control: public, max-age=31536000, immutable

// 3. Gambar: cache menengah/panjang
Cache-Control: public, max-age=2592000

// 4. Data API: cache pendek + validasi
Cache-Control: private, max-age=60
ETag: "api-response-hash"

// 5. Service Worker untuk dukungan offline

❌ Hindari​

// buruk: cache lama untuk dokumen entry HTML
Cache-Control: max-age=31536000

// buruk: hanya mengandalkan Expires
Expires: Wed, 21 Oct 2025 07:28:00 GMT

// buruk: tidak ada header cache eksplisit

// buruk: kebijakan sama untuk semua jenis sumber daya
Cache-Control: max-age=3600

Pohon keputusan strategi cache​

Apakah ini aset statis?
β”œβ”€ Ya -> nama file punya hash?
β”‚ β”œβ”€ Ya -> cache immutable lama (max-age=31536000, immutable)
β”‚ └─ Tidak -> cache menengah/panjang (misal max-age=2592000)
└─ Tidak -> Apakah ini HTML?
β”œβ”€ Ya -> no-cache
└─ Tidak -> Apakah ini API?
β”œβ”€ Ya -> cache pendek + validasi (max-age=60 + ETag)
└─ Tidak -> tentukan berdasarkan frekuensi pembaruan

Referensi​