Mengoptimalkan penyajian file statis di RoadRunner: mengonfigurasi middleware static dengan forbid dan cache headers, memakai ETag serta last-modified, mengirim file besar lewat sendfile, dan menyusun strategi long-term caching untuk aset.

Di episode 5 kita sudah menyentuh http.static sebagai middleware. Pada episode kali ini kita memaksimalkannya: caching & static assets yang benar-benar dioptimalkan — header cache, ETag, kompresi, dan sendfile — supaya aset dilayani secepat mungkin dan bandwidth browser terhemat.
Mengapa episode ini penting? Karena aset statis (CSS, JS, gambar) adalah sebagian besar request di aplikasi web nyata. Jika aset sampai ke worker PHP, kalian membuang resource worker untuk pekerjaan yang seharusnya selesai di level Go dalam mikro detik. Episode ini menutup lubang performa paling umum.
http:
address: 0.0.0.0:8080
middleware: ["static", "gzip", "sendfile"]
static:
dir: public
forbid: [".php", ".htaccess"]
always: ["robots.txt", "favicon.ico"]
cache:
etag: true
last_modified: true| Key | Fungsi |
|---|---|
dir | Direktori root file statis |
forbid | Ekstensi yang tidak boleh dilayani (keamanan) |
always | File yang selalu dilayani meski ada worker handler dengan path sama |
cache.etag | Kirim header ETag untuk validasi cache |
cache.last_modified | Kirim header Last-Modified |
Saat browser meminta ulang file, header validasi menentukan apakah browser boleh pakai cache lokal:
ETag: server mengirim hash isi file. Browser membawa If-None-Match pada request berikutnya; bila hash cocok, server membalas 304 Not Modified (tanpa body) — hemat bandwidth total.Last-Modified: versi sederhana berbasis waktu modifikasi file, divalidasi lewat If-Modified-Since.Keduanya diaktifkan hanya dengan cache.etag: true dan cache.last_modified: true. Untuk file yang berubah-ubah (konten dinamis), keduanya diabaikan karena respons tidak berasal dari static.
Uji dengan curl:
curl -I http://localhost:8080/assets/app.css
curl -I -H "If-None-Match: <etag-dari-respons>" http://localhost:8080/assets/app.cssRespons kedua harus HTTP 304 — konfirmasi cache validasi bekerja.
Tip
Pasangkan dengan gzip di middleware supaya aset teks (CSS/JS/HTML) dikompresi sebelum dikirim. Urutan ["static", "gzip", "sendfile"] membuat Go: (1) menemukan file, (2) mengompresnya, (3) mengirim via kernel.
Middleware sendfile memakai syscall kernel sendfile(2) untuk mengirim file langsung dari disk ke socket, tanpa membaca seluruhnya ke memory Go:
http:
middleware: ["static", "sendfile"]Kapan berguna? Untuk file besar seperti video, archive, atau font besar yang diunduh ribuan kali. Tanpa sendfile, file 500 MB akan dimuat ke memory Go lalu disalin ke socket — boros memory dan CPU. Dengan sendfile, kernel yang menangani transfer — memory Go hampir tidak terpakai.
Aset yang namanya mengandung hash konten (hasil build Vite/Webpack) aman di-cache selama mungkin — isinya tidak akan berubah selama nama file tidak berubah. Tambahkan header Cache-Control untuk aset statis:
http:
middleware: ["static", "headers", "gzip"]
headers:
response:
"Cache-Control": "public, max-age=31536000, immutable"Simpulan strategi cache:
| Jenis File | Header | Alasan |
|---|---|---|
assets/build-*.{js,css} (hash) | immutable, 1 tahun | Isi tetap selama nama berubah |
| HTML, manifest | Tanpa cache agresif | Harus selalu fresh |
| Gambar statis | max-age=604800 (1 minggu) | Berubah jarang, tanpa hash di nama |
| API responses | Jangan cache browser | Berbasis logika bisnis |
Warning
Jangan pasang immutable global untuk semua file. Hanya aset yang ber-version (nama file memuat hash isi) yang aman dengan cache 1 tahun. Untuk file biasa, gunakan max-age wajar agar perubahan tetap terdeteksi.
| Kesalahan | Dampak | Solusi |
|---|---|---|
forbid tidak lengkap | Source .php/.env bocor | Set forbid: [".php", ".htaccess", ".env", ".git"] |
| Aset tanpa cache header | Bandwidth boros, TTFB lambat | Set Cache-Control via headers |
| URL aset tanpa hash + cache lama | User melihat versi lama | Cache immutable hanya untuk file ber-version |
| Statis di-serve lewat PHP | Worker penuh untuk aset | Pastikan static di posisi pertama middleware |
Pada episode 13 ini, kalian telah mengoptimalkan static assets.
Inti yang harus dibawa pulang:
http.static melayani file dari dir dengan forbid untuk keamanan.ETag/Last-Modified mengaktifkan validasi cache (304).sendfile mengirim file besar via kernel — hemat memory Go.Cache-Control agresif hanya untuk aset ber-version.forbid; jangan pernah menyentuh PHP untuk aset.Di episode 14 selanjutnya, kita belajar sessions, state & stateless best practice — mengapa worker persistent melarang state request-scoped, bagaimana mengelola session dengan aman, dan praktik refactor aplikasi agar worker-safe. Sampai jumpa di episode 14!