Halo Semua, kali ini saya akan sharing tentang rate limiter di golang. rate limiter sendiri adalah sebuah metode untuk membatalkan request dari pengguna yang terlalu banyak dalam waktu bersamaan.
Yang Ingin Membantu Saya Untuk Terus Berkontribusi Boleh Banget Klik Dibawah
Implementasi
Kita membuat sebuah folder bernama middleware dan di dalamnya buat sebuah file bernama limiter.go
packagemiddlewareimport ("log""net""net/http""sync""time""golang.org/x/time/rate")// getVisitortypevisitorstruct { limiter *rate.Limiter lastSeen time.Time}var visitors =make(map[string]*visitor)var mu sync.Mutex// menjalankan di belakang clean up visitorfuncinit() {gocleanupVisitors()}// membersihkan map visitor ketika sudah tiga menitfunccleanupVisitors() {for { time.Sleep(time.Minute) mu.Lock()for ip, v :=range visitors {if time.Since(v.lastSeen) >3*time.Minute {delete(visitors, ip) } } mu.Unlock() }}// menangkap semua pengunjung berdasarkan ip yang melakukan requestfuncgetVisitor(ip string) *rate.Limiter { mu.Lock()defer mu.Unlock() v, exists := visitors[ip]// mengecheck apakah ip ini ada// jika tidak ada daftarkan ipnya di mapif!exists {// setiap satu detik hanya ada 15 request yang diperbolahkan limiter := rate.NewLimiter(1, 15)// menyimpan ip dan menetapkan limiter visitors[ip] =&visitor{limiter, time.Now()}return limiter }// ketika ip ditemukan jalankan limiter dari ip itu// Update waktu terakhir dia request v.lastSeen = time.Now()return v.limiter}// ini bisa di gunakan nanti sebagai middlewarefuncLimiter(h http.Handler) http.Handler {return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {var host, _, err = net.SplitHostPort(r.RemoteAddr)if err !=nil { log.Print(err.Error()) http.Error(w, "Internal Server Error", http.StatusInternalServerError)return }// check visitorvar limiter =getVisitor(host)// jika limit penuh return error to many requestif!limiter.Allow() { http.Error(w, http.StatusText(http.StatusTooManyRequests), http.StatusTooManyRequests)return } h.ServeHTTP(w, r) })}
isikan dengan
packagemainimport ("log""net/http" limit "github.com/aryadiahmad4689/rate-limit-go/middleware")funcokHandler(w http.ResponseWriter, r *http.Request) { w.Write([]byte("OK"))}funcmain() { mux := http.NewServeMux() mux.HandleFunc("/", okHandler)// Wrap the servemux with the limit middleware. log.Print("Listening on :4000...") http.ListenAndServe(":4000", limit.Limiter(mux))}
packagemainimport ("fmt""io/ioutil""net/http""time")functest() { c :=http.Client{Timeout: time.Duration(1) * time.Second} resp, err := c.Get("http://localhost:4000")if err !=nil { fmt.Printf("Error %s", err)return }defer resp.Body.Close() body, err := ioutil.ReadAll(resp.Body) fmt.Printf("Body : %s", body)}funcmain() {var i intfor i =0; i <20; i++ {test() fmt.Println(i) }}
jalankan server terlebih dahulu baru jalankan root main.go dan hasilnya
lihat hasilnya ketika request ke lima belas dia akan mengembalikan error bahwa request terlalu banyak.
Yang Ingin Membantu Saya Untuk Terus Berkontribusi Boleh Banget Klik Dibawah
Kita membuat sebuah function public bernama limiter yang melewati http handler. function ini digunakan untuk menangkap semua request yang masuk berdasarkan ip dan di validasi oleh get visitor. untuk penjelasan silahkan lihat komentar di codenya.
Coba Kita Test
kita membuat sebuah folder bernama server dialamnya ada file bernama server.go
untuk di root main.go isikan dengan
foldenya sekarang seperti
Itulah teman teman tentang rate-limiter di golang. semoga membantu