Go Middleware net/http
Definisi
Middleware di Go net/http adalah fungsi yang membungkus http.Handler menjadi handler baru, menambahkan perilaku (logging, auth, CORS) sebelum meneruskan ke handler inti. Karena http.Handler sangat sederhana, middleware biasanya dibuat dengan pola func(next http.Handler) http.Handler.
Kapan dipakai
Pakai middleware untuk kekhawatiran lintas-cutting yang berlaku untuk banyak route: autentikasi, logging request, recovery dari panic, compression, rate limit sederhana. Jangan taruh logika bisnis spesifik endpoint di middleware; itu tugas handler.
Cara kerja
Middleware tunggal
func Logging(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
log.Printf("%s %s", r.Method, r.URL.Path)
next.ServeHTTP(w, r)
})
}Chain manual
handler := Logging(Auth(MyHandler{}))Helper chain
type Middleware func(http.Handler) http.Handler
func Chain(h http.Handler, mws ...Middleware) http.Handler {
for i := len(mws) - 1; i >= 0; i-- {
h = mws[i](h)
}
return h
}
// pemakaian
final := Chain(handler, Logging, Auth, Recover)Iterasi mundur penting: middleware paling kiri dieksekusi paling pertama saat request masuk.
Struktur alur
Contoh auth middleware
func Auth(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
if r.Header.Get("X-API-Key") != os.Getenv("API_KEY") {
http.Error(w, "unauthorized", http.StatusUnauthorized)
return
}
next.ServeHTTP(w, r)
})
}Catatan implementasi
- Panggil
next.ServeHTTPtepat satu kali, atau response akan dobel/terlewat. - Untuk memotong request (misal 401), jangan panggil
next, cukup tulis response lalu return. - Bawa nilai antar middleware lewat
context.WithValue(r.Context(), ...)lalur.WithContext(...). http.StripPrefixdanhttp.TimeoutHandlersudah ada sebagai middleware bawaan berguna.
Kesalahan umum
- Lupa panggil next: request hang / response kosong.
- Memanggil next dua kali: header sudah terkirim lalu panik "superfluous WriteHeader".
- Urutan salah: chain dibalik sehingga auth jalan setelah handler utama.
- Mutasi response tanpa flusher: menambahkan header setelah write tidak berlaku.
- Context tidak di-pass:
r.WithContextlupa dipakai, nilai hilang di handler.