httprate - HTTP Rate Limiter
net/http
request rate limiter based on the Sliding Window Counter pattern inspired by
CloudFlare https://blog.cloudflare.com/counting-things-a-lot-of-different-things.
The sliding window counter pattern is accurate, smooths traffic and offers a simple counter
design to share a rate-limit among a cluster of servers. For example, if you'd like
to use redis to coordinate a rate-limit across a group of microservices you just need
to implement the httprate.LimitCounter
interface to support an atomic increment and get.
Backends
Example
package main
import (
"net/http"
"github.com/go-chi/chi/v5"
"github.com/go-chi/chi/v5/middleware"
"github.com/go-chi/httprate"
)
func main() {
r := chi.NewRouter()
r.Use(middleware.Logger)
r.Use(httprate.LimitByIP(100, time.Minute))
r.Get("/", func(w http.ResponseWriter, r *http.Request) {
w.Write([]byte("."))
})
http.ListenAndServe(":3333", r)
}
Common use cases
Rate limit by IP and URL path (aka endpoint)
r.Use(httprate.Limit(
10,
10*time.Second,
httprate.WithKeyFuncs(httprate.KeyByIP, httprate.KeyByEndpoint),
))
Rate limit by arbitrary keys
r.Use(httprate.Limit(
100,
time.Minute,
httprate.WithKeyFuncs(func(r *http.Request) (string, error) {
return r.Header.Get("X-Access-Token"), nil
}),
))
Send specific response for rate limited requests
r.Use(httprate.Limit(
10,
time.Minute,
httprate.WithLimitHandler(func(w http.ResponseWriter, r *http.Request) {
http.Error(w, "some specific response here", http.StatusTooManyRequests)
}),
))
r.Use(httprate.Limit(
1000,
time.Minute,
httprate.WithResponseHeaders(httprate.ResponseHeaders{
Limit: "X-RateLimit-Limit",
Remaining: "X-RateLimit-Remaining",
Reset: "X-RateLimit-Reset",
RetryAfter: "Retry-After",
Increment: "",
}),
))
r.Use(httprate.Limit(
1000,
time.Minute,
httprate.WithResponseHeaders(httprate.ResponseHeaders{}),
))
LICENSE
MIT