Rate Limiting in Spring WebFlux
Last Updated :
16 Jul, 2024
Rate limiting is a crucial technique to control the amount of incoming traffic to the server. This prevents abuse, ensures fair resource usage, and protects against potential Denial of Service (DOS) attacks. In the Spring WebFlux, rate limiting can be implemented effectively using the Spring Cloud Gateway. This article will guide setting up the rate limiting in the Spring WebFlux application.
Rate limiting restricts the number of requests the client can make to the server within the specified period. In Spring WebFlux, it can be achieved using Spring Cloud Gateway with Redis as the backing store to track the request counts and limits of the Spring application.
Key Components
- Spring Cloud Gateway: The library that provides a simple, yet powerful way to route API requests of the application.
- Redis: An in-memory data structure store that can be used as the database, cache, and message broker.
- KeyResolver: The component that resolves the key for the rate-limiting and is typically based on the client IP or user identity.
Prerequisites:
- Good understanding of the Spring Boot and Spring Reactive.
- Basic understanding of the Rate Limiting concept.
- JDK and IntelliJ Idea setup installed in your local system.
- Maven for building dependency management.
Implementation of Rate Limiting in Spring WebFlux
Step 1: Create a Spring Project
Create a new Spring Boot project using spring Initializr and add the below dependencies.
Dependencies:
- Spring Web Reactive
- Lombok
- Spring DevTools
After creating the project, the folder structure will be like below image in the IDE.
Step 2: Configure the Application Properties
Now, configure the application property of the project by the adding the below properties:
spring.application.name=example-ratelimit
server.port=8081
Step 3: Create the GreetController class
Java
package org.example.exampleratelimit;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;
@RestController // Annotation to define this class as a RESTful web service controller
@RequestMapping("/greet") // Maps HTTP requests to /greet to methods in this controller
public class GreetingController {
@GetMapping // Annotation to map HTTP GET requests to this method
public Mono<String> greet(ServerWebExchange exchange) {
// Create a Mono that emits a greeting message
return Mono.just("Hello, Welcome to Spring WebFlux with Rate Limiting!")
.doOnSuccess(message -> {
// Add custom headers to the response for rate limiting information
exchange.getResponse().getHeaders().add("X-RateLimit-Limit", "10"); // Maximum allowed requests
exchange.getResponse().getHeaders().add("X-RateLimit-Remaining", ""); // Remaining requests
exchange.getResponse().getHeaders().add("X-RateLimit-Reset", ""); // Time until the rate limit resets
});
}
}
This code defines a Spring WebFlux REST controller that handles HTTP GET requests to the /greet
endpoint. It returns a greeting message and adds custom headers to the response for rate limiting information, such as the request limit, remaining requests, and the reset time.
Step 4: Main class
No changes are required in the main class.
Java
package org.example.exampleratelimit;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class ExampleRatelimitApplication {
public static void main(String[] args) {
SpringApplication.run(ExampleRatelimitApplication.class, args);
}
}
pom.xml file:
XML
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>3.3.0</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>org.example</groupId>
<artifactId>example-ratelimit</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>example-ratelimit</name>
<description>example-ratelimit</description>
<properties>
<java.version>17</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-webflux</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<scope>runtime</scope>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>io.projectreactor</groupId>
<artifactId>reactor-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<excludes>
<exclude>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</exclude>
</excludes>
</configuration>
</plugin>
</plugins>
</build>
</project>
Step 5: Run the application
Now, run the application and it will start at port 8081 of Netty server.
Setup the Gateway Service
Step 1: Create the Spring Project
Create a new Spring Boot project using spring Initializr and add the below dependencies.
Dependencies:
- Spring Web Reactive
- Lombok
- Spring DevTools
- Spring Cloud Gateway
After creating the project, the folder structure will be like below image:
Step 2: Configure the Application Properties
spring:
cloud:
gateway:
routes:
- id: greeting_route
uri: http://localhost:8081
predicates:
- Path=/greet
filters:
- name: RequestRateLimiter
args:
key-resolver: "#{@userKeyResolver}"
redis-rate-limiter.replenishRate: 1
redis-rate-limiter.burstCapacity: 1
data:
redis:
port: 6379
host: localhost
Step 3: Create the RateLimitingConfig Class
Java
package org.example.ratelimitgateway;
import org.springframework.cloud.gateway.filter.ratelimit.KeyResolver;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import reactor.core.publisher.Mono;
@Configuration // Indicates that this class contains Spring configuration
public class RateLimitingConfig {
@Bean // Defines a bean for the application context
public KeyResolver userKeyResolver() {
// Resolves the key for rate limiting based on the client's IP address
return exchange -> Mono.just(exchange.getRequest().getRemoteAddress().getAddress().getHostAddress());
}
}
This code defines a configuration class for rate limiting in a Spring Cloud Gateway application. It includes a KeyResolver
bean that resolves the key for rate limiting based on the client's IP address. The resolved key is used to track and limit requests from individual clients.
Step 4: Main Class
No changes are required in the main class.
Java
package org.example.ratelimitgateway;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class RatelimitGatewayApplication {
public static void main(String[] args) {
SpringApplication.run(RatelimitGatewayApplication.class, args);
}
}
pom.xml file:
XML
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>3.3.0</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>org.example</groupId>
<artifactId>ratelimit-gateway</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>ratelimit-gateway</name>
<description>ratelimit-gateway</description>
<properties>
<java.version>17</java.version>
<spring-cloud.version>2023.0.2</spring-cloud.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-webflux</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-gateway</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-circuitbreaker-reactor-resilience4j</artifactId>
</dependency>
<dependency>
<groupId>io.github.resilience4j</groupId>
<artifactId>resilience4j-spring-boot2</artifactId>
<version>1.7.1</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis-reactive</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<scope>runtime</scope>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>${spring-cloud.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<excludes>
<exclude>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</exclude>
</excludes>
</configuration>
</plugin>
</plugins>
</build>
</project>
Step 5: Run the application
Now run this and it will start at port 8080 in Netty server.
Testing the Application
Note: When the rate limit is exceeded then the server responds with the 429 Too Many Requests status code.
GET http://localhost:8080/greet
Output:
By using Spring Cloud Gateway and Redis, we can easily set up and configure the rate limiting based on the client IP addresses or other criteria.
Similar Reads
Logging in Spring WebFlux Logging in Spring WebFlux is important for monitoring, debugging, and tracing the flow of requests through the reactive application. Here is how to effectively use logging in a Spring WebFlux application. There are log logger frameworks available in the market to handle logs in the software applicat
5 min read
Pagination in Spring Webflux The Spring WebFlux is part of Spring Framework and this allows developers to develop non-blocking applications. It provides different operators to handle the publisher and consumers in the application by using Spring reactor. In this article, we explain what is pagination and its uses in web softwar
4 min read
Retry in Spring WebFlux The Spring WebFlux is part of the Spring Framework And It allows developers to develop nonblocking applications. In reactive programming lot of operators are available to handle to publishers and consumers. In this article, we will explain about retry operator in WebFlux with related examples. Retry
5 min read
Event loop in Spring WebFlux Spring WebFlux is a version of the Spring Framework that supports reactive programming, allowing for non-blocking, asynchronous code execution. At the core of its framework, the event loop model is designed to efficiently handle multiple simultaneous requests. For example, if there are multiple even
5 min read
Spring WebFlux Testing In Spring Boot, Spring WebFlux is the reactive programming framework that can provide support for the building of asynchronous, non-blocking, and event-driven applications when it comes to testing in the spring WebFlux. Key Terminologies:Unit Testing: It can involve testing individual components of
9 min read