有些时候,为了防止我们上线的网站被攻击,或者被刷取流量,我们会对某一个ip进行限制处理,这篇文章,我们将通过Spring Boot编写一个小案例,来实现在一分钟内同一个IP只能访问10次,当然具体数值,是您来决定,废话不多说,上代码。
首先,我们需要在Spring Boot的pom.xml文件中插入我们需要的依赖。具体的依赖部分我给出如下,也是Spring Boot常用的依赖,当然我并未在pom文件中给出Spring Boot的使用版本,因为我觉得并不是每个人都使用同样的版本,这是我使用的:
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-test</artifactId><scope>test</scope><exclusions><exclusion><groupId>org.junit.vintage</groupId><artifactId>junit-vintage-engine</artifactId></exclusion></exclusions></dependency><dependency><groupId>org.apache.tomcat.embed</groupId><artifactId>tomcat-embed-core</artifactId></dependency><dependency><groupId>org.springframework</groupId><artifactId>spring-webmvc</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><dependency><groupId>org.springframework</groupId><artifactId>spring-web</artifactId></dependency>
既然说到是对ip访问的限制,那么我们可以通过拦截器来实现对同一个ip地址在同一段时间段内的多次访问进行限制。具体代码如下:
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.HandlerInterceptor;import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.HashMap;
import java.util.Map;
import java.util.Timer;
import java.util.TimerTask;/*** @author Miaow.Y.Hu* @date 2023年10月24日 19:01* @description*/@Component
public class RateLimitInterceptor implements HandlerInterceptor {private static final int MAX_REQUESTS = 10; // 同一时间段内允许的最大请求数private static final long TIME_PERIOD = 60 * 1000; // 时间段,单位为毫秒 在一分钟内限制ip访问次数为10次private Map<String, Integer> requestCounts = new HashMap<>();@Overridepublic boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {String ipAddress = request.getRemoteAddr();System.out.println(ipAddress);// 检查 IP 地址是否已经达到最大请求数if (requestCounts.containsKey(ipAddress) && requestCounts.get(ipAddress) >= MAX_REQUESTS) {response.setStatus(429); //设置响应状态码response.getWriter().write("Too many requests from this IP address");return false;}// 更新 IP 地址的请求数requestCounts.put(ipAddress, requestCounts.getOrDefault(ipAddress, 0) + 1);// 在指定时间后清除 IP 地址的请求数new Timer().schedule(new TimerTask() {@Overridepublic void run() {requestCounts.remove(ipAddress);}},TIME_PERIOD);return true;}
}
在这段代码中,我们使用了一个Map来存储每个IP地址的请求数,在preHandle方法中,我们首先检查IP地址的请求数是否已经达到最大请求数,如果是,则返回一个429当前IP地址的请求次数太多,一分钟只能请求10次,当然这决定权在你,然后我们更新IP地址的请求数,并在指定的时间段后清除该IP地址的请求数。
接下来,我们需要在配置类中注册拦截器,我采用的事WebMvcConfig:
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;@Configuration
public class WebMvcConfig implements WebMvcConfigurer {private final RateLimitInterceptor rateLimitInterceptor;@Autowiredpublic WebMvcConfig(RateLimitInterceptor rateLimitInterceptor) {this.rateLimitInterceptor = rateLimitInterceptor;}@Overridepublic void addInterceptors(InterceptorRegistry registry) {registry.addInterceptor(rateLimitInterceptor);}
}
在本段代码中,我们通过构造函数注入 RateLimitInterceptor
,然后在 addInterceptors
方法中将拦截器添加到拦截器注册表中。
现在,当同一 IP 地址在同一时间段内的请求数达到最大限制时,它将收到一个 429的响应。你可以根据自己的需求调整最大请求数和时间段。
需要注意的是,这个小案例只是简答实现了对IP地址的拦截,在实际开发中,我们需要做的东西更加多,考虑的情况也需要更加全面,利用更加复杂的逻辑和持久化的存储来处理IP地址的请求限制。
接下来,我们通过Controller类来测试我们的写的案例是否实现这个功能:
@RestController
@RequestMapping("user/")
public class UserController {@RequestMapping("demo")public String test(){return "测试";}@RequestMapping("userDemo")public User userDemo(User user){return user;}
}
User其实可写可不写,但是便于重复利用,我这里给出User的实体类吧:
public class User {private Long id;private String name;private Integer age;public Long getId() {return id;}public void setId(Long id) {this.id = id;}public String getName() {return name;}public void setName(String name) {this.name = name;}public Integer getAge() {return age;}public void setAge(Integer age) {this.age = age;}@Overridepublic boolean equals(Object o) {if (this == o) return true;if (o == null || getClass() != o.getClass()) return false;User user = (User) o;return Objects.equals(id, user.id) && Objects.equals(name, user.name) && Objects.equals(age, user.age);}@Overridepublic int hashCode() {return Objects.hash(id, name, age);}public User() {}public User(Long id, String name, Integer age) {this.id = id;this.name = name;this.age = age;}
}
最终结果展示: