Manage request rate limiting as you see fit with RateLimiting
in your Ktor server, ensuring you protect your
application from potential abuse or resource overload.
-
Token Bucket: Supports variable request rate and is suitable for handling bursts of requests.
-
Leaky Bucket: Guarantees a constant request rate, providing fair distribution between clients
-
Sliding Window: Allows a specific weight of calls to be made over a designated duration, considering the rate and call weight configured.
-
Configurable capacity unit of measure: Measure call count or call weight in bytes
-
Configurable call weighting: Calls can be made to take up more capacity based on a given function
-
Whitelist & Blacklist:
- Whitelist or blacklist based on the client's host, user-agent, or principal.
-
Customizable Response: Set your custom response when the rate limit is exceeded. The default response status is
429 Too Many Requests
. -
Logging: Log rate limit hits for better monitoring and debugging.
To apply the RateLimitingPlugin
, you need to install
it in your Ktor route and configure as per your requirements:
routing {
route("limited-route") {
install(RateLimiting) {
rateLimiter {
type = TokenBucket::class
rate = 1.seconds
capacity = 100
}
whiteListedHosts = setOf("trusted-host.com")
blackListedAgents = setOf("malicious-agent")
rateLimitExceededHandler = { rateLimiterResponse ->
respond(HttpStatusCode.TooManyRequests, rateLimiterResponse.message)
...
}
}
get {
call.respondText("Welcome to our limited route!")
}
}
}
install(RateLimiting) {
// Configuring Rate Limiter
type = TokenBucket::class, // Using Token Bucket rate limiting strategy
rate = 10.milliseconds, // 1 token is added per 10 milliseconds
capacity = 1000, // Up to 1000 tokens can be held for bursty traffic
clock = { Clock.System.now().toEpochMilliseconds() }, // Using system time
callVolumeUnit = CallVolumeUnit.Calls() // Measuring by the number of API calls
)
// Whitelisting Configurations
whiteListedHosts = setOf("192.168.1.1") // IP address exempted from rate limiting
whiteListedPrincipals = setOf(Principal("trustedUser")) // Trusted user with unrestricted access
whiteListedAgents = setOf("trusted-agent") // A user-agent that is allowed unrestricted access
// Blacklisting Configurations
blackListedHosts = setOf("192.168.1.2") // IP address completely restricted from API access
blackListedPrincipals = setOf(Principal("maliciousUser")) // User that is denied access to the API
blackListedAgents = setOf("malicious-agent") // A user-agent that is blocked from making API calls
// Handlers
blackListedCallerCallHandler = { call ->
// Respond with a 403 Forbidden status to blacklisted callers
call.respond(HttpStatusCode.Forbidden, "You are blacklisted and cannot access the API.")
}
callAcceptedHandler = { notLimited ->
// Add rate-limiting headers for accepted calls
response.headers.append("X-RateLimit-Remaining", "${notLimited.remaining}")
response.headers.append("X-RateLimit-Measured-by", notLimited.rateLimiter.callVolumeUnit.name)
}
rateLimitExceededHandler = { limitedBy ->
// Respond with a 429 status and appropriate headers for rate-limited callers
respond(HttpStatusCode.TooManyRequests, "Rate limit exceeded: ${limitedBy.message}")
response.headers.append("X-RateLimit-Limit", "${limitedBy.rateLimiter.capacity}")
response.headers.append("X-RateLimit-Measured-by", limitedBy.rateLimiter.callVolumeUnit.name)
response.headers.append("X-RateLimit-Reset", "${limitedBy.resetIn.inWholeMilliseconds}")
}