Ketika middleware Nuxt.js SSR dijalankan, tim menemukan perbedaan respons antara permintaan langsung ke server dan versi yang disajikan melalui cache edge. Lagi-lagi cache inconsistent muncul karena state yang kadang ter-reset, header yang tidak valid, dan race condition saat caching. Artikel ini langsung menjelaskan gejala yang diamati, akar masalah terkonfirmasi, serta langkah konkrit agar developer Nuxt.js bisa mencegah dan memperbaiki sendiri pola serupa.

Gejala: Request Langsung vs Cache Edge Bersikap Berbeda

Permintaan langsung pada URL API SSR menghasilkan data lengkap dan waktu respons sekitar 120ms. Namun, versi yang melewati edge cache sering kali mengembalikan payload stale, header x-cache "HIT", tetapi dengan tubuh yang tidak sesuai dengan status authentikasi terakhir. Log juga mencatat latency meningkat drastis ketika cache edge menyajikan respons, yang menandakan middleware tidak masuk dalam jalur yang sama.

  • Log request: middleware mengeksekusi, session valid, token refresh. Namun versi cached tidak terlihat masuk ke middleware sama sekali.
  • Header: respons edge memiliki cache-control: public, max-age=300 tapi tidak menyertakan vary: cookie, authorization.
  • Latency: request edge hit rata-rata 340ms, dengan spike 1 detik saat cache invalidasi bersamaan.

Poin utama: cache menyajikan respons lama tanpa memvalidasi state middleware. Ini bukan bug Nuxt.js API secara langsung melainkan kombinasi cache edge dan konfigurasi middleware SSR.

Diagnosa Akar Masalah

Cache Blur akibat Header Tidak Lengkap

Edge cache menyimpan respons yang seharusnya beragam untuk tiap session. Tanpa Vary, cache menganggap respons identik untuk semua pengguna. Akibatnya, middleware hanya dipanggil saat cache miss, sehingga request berikutnya tidak lagi mengecek autentikasi atau izin.

Race Condition pada State Middleware

Beberapa middleware menulis data ke context (event.context.auth) secara asinkron dengan await useFetch(). Ketika edge cache menunggu respons pertama, middleware melanjutkan dengan data yang belum stabil. Jika cache menyanndingkan respons yang belum selesai, hasil akhir bisa berisi state parsial dan menyebabkan invalid headers.

Header Invalid dan Observability Terbatas

Header seperti x-cache dan x-edge tidak dipantau secara sistematik. Log API hanya mencatat status 200, sementara detail cache/log request terpisah di CDN. Tanpa trace ID yang konsisten dan log middleware, sulit memastikan apakah request melewati versi cached atau langsung.

Perbaikan Konkrit

Atur Cache-Control dan Vary di Middleware

Pastikan middleware menetapkan header berikut sebelum mengirim respons, terutama bila respons bergantung pada cookie atau header otorisasi:

event.res.setHeader('cache-control', 'private, max-age=0, s-maxage=300, stale-while-revalidate=60');
event.res.setHeader('vary', 'cookie, authorization');

Cache global (CDN atau edge) sekarang tahu bahwa setiap request dengan cookie/authorization berbeda harus memperlakukan respons sebagai unik. s-maxage membolehkan cache edge menyimpan sementara tanpa mempengaruhi cache browser.

Validasi dan Freeze State Middleware

Tambahkan validasi eksplisit sebelum menyimpan state dalam middleware agar race condition bisa dideteksi. Contoh pola:

export default defineNuxtRouteMiddleware(async (to, from) => {
  const session = await useSession();
  if (!session?.user) {
    throw createError({ statusCode: 401, statusMessage: 'Unauthorized' });
  }
  to.meta.userId = session.user.id;
});

Status menjadi deterministik: middleware hanya meneruskan request jika state lengkap. Jika middleware menciptakan side-effect (misalnya fetch data tambahan), selesaikan semua promise sebelum respons di-cache.

Tingkatkan Observabilitas Cache

Tambahkan header yang menandai jalur eksekusi, misalnya:

event.res.setHeader('x-middleware-status', 'done');
event.res.setHeader('x-cache-debug', event.req.headers['x-cache'] || 'none');

Gabungkan dengan trace ID unik (mis. header x-request-id) sehingga log middleware, edge cache, dan API bisa di-correlate. Dengan ini, pengembang bisa melihat apakah cache men-skip middleware atau tidak.

Pola Preventif untuk Developer Nuxt.js

  • Selalu set Vary saat respons tergantung header dinamis seperti cookie atau authorization. Tanpa ini, generic cache mengacaukan API SSR.
  • Jangan cache body sebelum middleware selesai. Pastikan semua await selesai dan validasi selesai sebelum header cache-control keluar.
  • Gunakan trace ID konsisten. Header x-request-id atau x-response-id membantu menelusuri apakah respons cached atau langsung.
  • Monitor latency dan x-cache header. Spike latency bersama header x-cache: HIT menandakan cache melayani respons tanpa menjalankan middleware.

Pola ini relevan untuk tim frontend yang menulis middleware di Nuxt.js, serta backend engineer yang mengandalkan API SSR dengan caching edge. Dengan kombinasi cache-control yang tepat, validasi state, dan observabilitas tambahan, cache inconsistent bisa dicegah sekaligus mempermudah debugging.

Langkah Debugging Jika Terjadi Lagi

  1. Periksa log middleware dan pastikan trace ID diteruskan ke edge/CDN.
  2. Cek header cache-control dan vary pada respons cache vs direct.
  3. Tinjau state middleware: apakah semua async selesai sebelum respons? Gunakan unit test middleware untuk mensimulasikan request cached.
  4. Jika perlu, atur flag experiment, misalnya header x-cache-bypass, untuk memaksa middleware berjalan di cache.

Diagnosa dan perbaikan ini membantu tim memahami perbedaan request langsung dan cache edge pada Nuxt.js API serta mencegah cache inconsistent di masa depan.