Anatomi Masalah: Polusi Cache Edge pada Rilis Produksi
Pengguna mendapati tampilan antarmuka web rusak pasca-deployment: browser langsung merender respons mentah (raw JSON) seperti {"component":"Dashboard","props":{...},"url":"/dashboard","version":"..."} alih-alih antarmuka berbasis HTML lengkap. Masalah ini terjadi secara sporadis pada pengguna direct visit atau saat melakukan hard refresh (F5), sementara navigasi berbasis Single Page Application (SPA) internal tetap berjalan normal.
Root Cause: Cache Key Collision Tanpa Header 'Vary: X-Inertia'
Inertia.js menggunakan arsitektur dual-response pada URI yang identik. Perilaku respons dikendalikan oleh header permintaan klien:
- Direct Visit: Browser mengirimkan permintaan GET biasa tanpa header khusus. Backend merespons dengan status
200 OK,Content-Type: text/html, dan membungkus data aplikasi di dalam atribut rootdata-page. - Inertia Visit: Router sisi klien mengirimkan permintaan AJAX/Fetch dengan menyertakan header HTTP
X-Inertia: true. Backend merespons dengan status200 OK,Content-Type: application/json, dan payload data halaman saja.
Ketika CDN dikonfigurasi untuk melakukan caching terhadap rute web dinamis (misalnya untuk menghemat beban origin server), cache key default CDN hanya mengevaluasi Host + Path + Query String. CDN mengabaikan header HTTP request.
Urutan kegagalan terjadi sebagai berikut:
- Klien melakukan navigasi SPA via Inertia ke rute
/dashboard. Permintaan menyertakan headerX-Inertia: true. - Origin server mengembalikan payload JSON dengan header
Cache-Control: public, max-age=3600, tetapi tanpa menyertakanVary: X-Inertia. - Edge CDN menyimpan payload JSON tersebut dengan cache key
example.com/dashboard. - Klien lain membuka
https://example.com/dashboardsecara langsung melalui address bar browser. Permintaan ini meminta dokumen HTML, bukan JSON. - Edge CDN mendapati cache hit untuk key
example.com/dashboarddan langsung mengembalikan payload JSON mentah ke browser. Browser merender representasi MIMEapplication/jsontanpa mengeksekusi runtime JavaScript frontend.
Observabilitas: Deteksi Dini Anomali Edge & Klien
Pencegahan degradasi layanan bergantung pada metrik edge log dan telemetri klien.
1. Edge Log Monitoring
Jalankan query analisis log CDN (Cloudflare Logpush, CloudWatch, atau Datadog) untuk mendeteksi mismatch antara Accept header/User-Agent dengan Content-Type respons:
SELECT
client_ip,
request_uri,
request_headers['user-agent'] AS user_agent,
response_headers['content-type'] AS content_type
FROM cdn_access_logs
WHERE request_headers['x-inertia'] IS NULL
AND response_headers['content-type'] LIKE '%application/json%'
AND request_uri NOT LIKE '/api/%'
AND status_code = 200;2. Alerting Mismatch Rasio Konten
Pasang alert dengan kondisi: lonjakan metrik edge.response.content_type.json melebihi 5% dari total lalu lintas pada rute non-API tanpa keberadaan header permintaan X-Inertia selama interval 2 menit.
3. Sentry / RUM Client-Side Tracking
Ketika raw JSON termuat di browser, berkas bundle JavaScript frontend tidak dieksekusi. Metrik RUM akan menunjukkan drop drastis pada interaksi Largest Contentful Paint (LCP) atau peningkatan error pada tracking error gateway/proxy fallback.
Mitigasi Cepat & Prosedur Rollback Darurat
Saat insiden terjadi, eksekusi pembersihan cache secara instan sebelum melakukan deploy perbaikan kode origin.
Langkah 1: Fast Purge via CDN API
Gunakan API CDN untuk menginvalidasi cache global pada rute-rute aplikasi Inertia:
curl -X POST "https://api.cloudflare.com/client/v4/zones/${ZONE_ID}/purge_cache" \
-H "Authorization: Bearer ${CLOUDFLARE_API_TOKEN}" \
-H "Content-Type: application/json" \
--data '{"prefixes": ["example.com/dashboard", "example.com/profile"]}'Jika skala URL terlalu luas, eksekusi purge total sementara ({"purge_everything": true}) sambil memantau kapasitas origin server terhadap thundering herd.
Langkah 2: Edge Rule Bypass Sementara
Tambahkan Transform Rule atau Cache Rule di level edge untuk mem-bypass cache secara eksplisit jika header X-Inertia ada atau jika rute mencakup antarmuka dinamis:
# Cloudflare Cache Rule Expression:
(http.request.uri.path not matches "^/(assets|build|static)/" and http.request.headers["x-inertia"][0] eq "true")
-> Action: Bypass CachePencegahan Permanen
1. Konfigurasi Backend Middleware (Header Vary)
Origin server wajib menginstruksikan reverse proxy bahwa respons bervariasi bergantung pada header X-Inertia. Pada Laravel, pasang logic ini pada middleware aplikasi:
namespace App\Http\Middleware;
use Closure;
use Illuminate\Http\Request;
use Symfony\Component\HttpFoundation\Response;
class EnsureVaryInertiaHeader
{
public function handle(Request $request, Closure $next): Response
{
/** @var Response $response */
$response = $next($request);
// Tambahkan Vary: X-Inertia ke seluruh respons berbasis Inertia atau web routes
$response->headers->set('Vary', 'X-Inertia, Accept', false);
// Pastikan halaman privat tidak tersimpan di public edge
if (! $request->is('public-routes/*')) {
$response->headers->set('Cache-Control', 'no-store, private');
}
return $response;
}
}2. Konfigurasi Cache Key Edge CDN
Jika CDN mendukung custom cache key (misalnya Cloudflare Enterprise Custom Cache Keys atau Fastly VCL), sertakan header X-Inertia ke dalam key:
# Konfigurasi Fastly VCL (vcl_hash)
sub vcl_hash {
set req.hash += req.url;
set req.hash += req.http.host;
if (req.http.X-Inertia) {
set req.hash += req.http.X-Inertia;
}
return (hash);
}3. Otomasi Purge pada Pipeline CI/CD
Invalidasi cache CDN wajib terikat langsung pada pipeline deployment setelah artefak baru aktif di server origin. Tambahkan task pada pipeline deployment (contoh GitHub Actions):
- name: Purge Edge Cache
env:
CF_TOKEN: ${{ secrets.CLOUDFLARE_API_TOKEN }}
CF_ZONE: ${{ secrets.CLOUDFLARE_ZONE_ID }}
run: |
curl -s -f -X POST "https://api.cloudflare.com/client/v4/zones/$CF_ZONE/purge_cache" \
-H "Authorization: Bearer $CF_TOKEN" \
-H "Content-Type: application/json" \
--data '{"tags": ["inertia-pages"]}'
echo "Edge cache purged successfully for new release."4. Automated Smoke Test di Pipeline CI/CD
Verifikasi isolasi respons via curl sebelum mengarahkan lalu lintas produksi seutuhnya:
#!/usr/bin/env bash
set -euo pipefail
TARGET_URL="https://staging.example.com/dashboard"
# 1. Uji Navigasi Direct Visit (Harus mengembalikan HTML)
HTML_CONTENT_TYPE=$(curl -s -o /dev/null -I -w "%{content_type}" "$TARGET_URL")
if [[ "$HTML_CONTENT_TYPE" != *"text/html"* ]]; then
echo "FAILED: Direct visit did not yield text/html, got: $HTML_CONTENT_TYPE"
exit 1
fi
# 2. Uji Navigasi AJAX Inertia (Harus mengembalikan JSON)
JSON_CONTENT_TYPE=$(curl -s -o /dev/null -I -w "%{content_type}" \
-H "X-Inertia: true" \
-H "Accept: text/html, application/xhtml+xml" \
"$TARGET_URL")
if [[ "$JSON_CONTENT_TYPE" != *"application/json"* ]]; then
echo "FAILED: Inertia visit did not yield application/json, got: $JSON_CONTENT_TYPE"
exit 1
fi
# 3. Verifikasi Keberadaan Header Vary
VARY_HEADER=$(curl -s -I -H "X-Inertia: true" "$TARGET_URL" | tr -d '\r' | grep -i '^vary:' || true)
if [[ "$VARY_HEADER" != *"X-Inertia"* ]]; then
echo "FAILED: Response missing 'Vary: X-Inertia' header. Edge cache collision imminent!"
exit 1
fi
echo "All edge cache verification tests passed."Kesimpulan
Caching respons dinamis pada arsitektur hybrid seperti Inertia.js menuntut pemisahan status state yang ketat. Mengandalkan path URL sebagai cache key tunggal tanpa mengevaluasi header X-Inertia melalui instruksi Vary akan selalu memicu polusi data cache. Otomasi invalidasi edge dan smoke test berbasis protokol HTTP pada CI/CD merupakan lapisan pertahanan wajib guna mencegah kebocoran raw JSON ke sisi pengguna akhir.
Komentar
0 komentar
Masuk ke akun kamu untuk ikut berkomentar.
Belum ada komentar
Jadilah yang pertama ikut berdiskusi!