Request ID
Deserve tidak punya middleware request ID, dan alasannya soal kepercayaan. Sebuah ID yang dihasilkan tak mengidentifikasi apa pun, jadi framework bersandar pada identitas yang benar-benar bisa dihitungnya, IP klien yang diresolusi.
Kenapa Tidak Dibawa
Sebuah middleware request ID mencap tiap request dengan nilai segar, biasanya dari crypto.randomUUID(). Tangkapannya adalah apa arti nilai itu. Sebuah ID yang dihasilkan server itu acak, jadi ia mengikat balik ke tak seorang pun dan tak membawa fakta tentang pemanggil. Sebuah X-Request-ID yang dipasok klien lebih buruk, karena klien bisa mengirim apa saja, mengulang nilai, atau mengaturnya ke 0xb33F...., dan mempercayai itu sebagai identitas adalah mempercayai header yang ditulis orang asing.
Jadi ID acak baik sebagai label log tapi salah sebagai sumber kebenaran. Deserve sudah mengawasi semua dari saat server menyala sampai saat sebuah request mencapai pengguna, lewat event siklus hidup, jadi sebuah ID sintetis terpisah seperti 0xb33F.... hanya mengulang yang sudah dilacak framework. Identitas yang bisa diandalkannya adalah yang patut diraih.
IP Adalah Sumber Kebenaran
Setiap request membawa ctx.ip, alamat klien yang diresolusi. Ia tak dibaca mentah dari header. Framework menelusuri rantai forwarding lewat hop tepercaya dan berhenti di hop pertama yang tak dipercayainya, jadi header palsu dari peer tak tepercaya tak pernah menang.
- Tanpa proxy tepercaya -
ctx.ipadalah peer TCP langsung, dan header forwarding diabaikan sepenuhnya. - Di belakang proxy tepercaya - rantai ditelusuri kanan ke kiri lewat hop tepercaya, menghormati
X-Forwarded-For, headerForwardedRFC 7239, dan header IP-tunggal seperticf-connecting-ip. - Dikonfigurasi sekali -
trustProxymemutuskan peer mana yang dianggap tepercaya, jadi mempercayainya adalah pilihan sengaja, bukan default.
Mempercayai sebuah proxy sepenuhnya benar hanya karena konfigurasinya berkata begitu. Sebuah framework yang menebak akan menangkap alamat yang salah, jadi Deserve membuat kepercayaan itu eksplisit dan menghitung sisanya.
Satu Request Tak Pernah Tumpang Tindih
Setiap request mendapat Context-nya sendiri, dibangun sekali saat request tiba dan hilang saat response dikirim. Tak ada request diproses dua kali, dan tak ada dua request berbagi state atau saling divalidasi. Sebuah ID sintetis untuk membedakan request menyelesaikan masalah yang tak ada, karena siklus hidup sudah menjaganya terpisah.
Mengkorelasi Tanpa ID Acak
Untuk mengkorelasi log, event siklus hidup sudah membawa apa yang dimaksudkan request ID. Setiap event request:complete menyertakan ip yang diresolusi, url, dan durationMs di metadata-nya, plus timestamp di amplopnya, jadi sebuah baris log mengidentifikasi request dari nilai asli ketimbang yang dibuat-buat.
router.on((event) => {
// Korelasi dengan IP dan waktu asli
if (event.kind === 'request:complete') {
const { ip, url } = event.metadata as { ip?: string, url: string }
console.log(`${event.timestamp} ${ip ?? 'unknown'} ${url}`)
}
})
await router.serve(8000)Ketika Sebuah Label Memang Membantu
Sebuah label berumur pendek untuk mengikat baris log dalam satu request tetap mungkin, dan ia tinggal di ctx.state seperti nilai per-request lain. Intinya memperlakukannya sebagai kemudahan, bukan identitas, karena jawaban tepercaya adalah ctx.ip.
router.use(async (ctx, next) => {
// Label untuk log, bukan kepercayaan
ctx.state.label = crypto.randomUUID()
return await next()
})Untuk konteks trace yang melintasi layanan, alat yang tepat adalah header traceparent yang dibahas di Distributed Tracing, bukan nilai per-request acak.