当前位置:   article > 正文

SpringBoot限制接口访问次数

springboot限制接口访问次数

Spring Boot 防止接口刷新,通常是指防止接口被频繁地进行相同或类似的请求。

可以通过多种方式来防止接口被恶意刷取,以下是一些常见的方法:

1. 使用拦截器(Interceptor):

- 创建一个拦截器类,实现`HandlerInterceptor`接口。
- 在拦截器中重写`preHandle`方法,实现访问频率限制的逻辑。
- 将拦截器注册到Spring MVC的拦截器链中,这样每次请求都会经过拦截器的处理。

2. 使用过滤器(Filter):

- 创建一个过滤器类,实现`Filter`接口。
- 在过滤器中实现对请求的处理逻辑,比如检查请求的频率。
- 将过滤器注册到Spring Boot的过滤器链中,确保所有请求都会通过这个过滤器。

3. 使用切面(Aspect):

- 创建一个切面类,并使用`@Aspect`注解声明它是一个切面。
- 在切面中定义切点(Pointcut)和通知(Advice),用于拦截特定的方法调用或对象访问。
- 在通知中实现防刷逻辑,比如记录访问次数和时间,判断是否超过阈值。

4. 使用限流组件:

- 利用第三方库如Bucket4j、Sentinel等来实现限流。
- 这些库通常提供了丰富的配置选项和策略,可以方便地集成到Spring Boot项目中。

5. 使用API网关:

- 如果使用微服务架构,可以在API网关层面实现限流。
- API网关如Zuul、Kong等通常提供限流功能,可以在网关级别控制流量。

6. 使用Nginx配置:

- 在Nginx配置文件中设置限流规则,控制客户端的连接数和请求速率。

以下是个简单的例子,采用自定义注解的方式,根据时间来判断访问的次数做为限制

自定义注解

  1. import org.springframework.core.annotation.*;
  2. import org.springframework.core.Ordered;
  3. import java.lang.annotation.*;
  4. /**
  5. * @Author:myth
  6. * @time
  7. * @Discription
  8. */
  9. @Documented
  10. @Target(ElementType.METHOD)
  11. @Retention(RetentionPolicy.RUNTIME)
  12. @Order(Ordered.HIGHEST_PRECEDENCE)
  13. public @interface RequestLimit {
  14. int count() default Integer.MAX_VALUE;
  15. long time() default 60000;
  16. }

主要实现类

  1. package com.example.common;
  2. import com.example.exception.CustomException;
  3. import org.aspectj.lang.JoinPoint;
  4. import org.aspectj.lang.annotation.Aspect;
  5. import org.aspectj.lang.annotation.Before;
  6. import org.slf4j.Logger;
  7. import org.slf4j.LoggerFactory;
  8. import org.springframework.stereotype.Component;
  9. import javax.servlet.http.HttpServletRequest;
  10. import java.util.HashMap;
  11. import java.util.Map;
  12. import java.util.Timer;
  13. import java.util.TimerTask;
  14. /**
  15. * @method: $
  16. * @description: 限制访问类
  17. * @date: $
  18. * @author: myth
  19. * @return $
  20. */
  21. @Aspect
  22. @Component
  23. public class RequestLimitContract{
  24. private static final Logger logger = LoggerFactory.getLogger("requestLimitLogger");
  25. private Map<String , Integer> redisTemplate = new HashMap<>();
  26. @Before("within(@org.springframework.web.bind.annotation.RestController *) && @annotation(limit)")
  27. public void requestLimit(final JoinPoint joinPoint , RequestLimit limit) throws RequestLimitException {
  28. try {
  29. Object[] args = joinPoint.getArgs();
  30. HttpServletRequest request = null;
  31. for (int i = 0; i < args.length; i++) {
  32. if (args[i] instanceof HttpServletRequest) {
  33. request = (HttpServletRequest) args[i];
  34. break;
  35. }
  36. }
  37. if (request == null) {
  38. throw new RequestLimitException("方法中缺失HttpServletRequest参数");
  39. }
  40. String ip = request.getLocalAddr();
  41. String url = request.getRequestURL().toString();
  42. String key = "req_limit_".concat(url).concat(ip);
  43. if (redisTemplate.get(key) == null || redisTemplate.get(key) == 0) {
  44. redisTemplate.put(key, 1);
  45. } else {
  46. redisTemplate.put(key, redisTemplate.get(key) + 1);
  47. }
  48. int count = redisTemplate.get(key);
  49. if (count > 0) {
  50. //创建一个定时器
  51. Timer timer = new Timer();
  52. TimerTask timerTask = new TimerTask() {
  53. @Override
  54. public void run() {
  55. redisTemplate.remove(key);
  56. }
  57. };
  58. //这个定时器设定在time规定的时间之后会执行上面的remove方法,也就是说在这个时间后它可以重新访问
  59. timer.schedule(timerTask, limit.time());
  60. }
  61. if (count > limit.count()) {
  62. logger.info("用户IP[" + ip + "]访问地址[" + url + "]超过了限定的次数[" + limit.count() + "]");
  63. throw new CustomException(ResultCode.LIMIT_NUMBER);
  64. }
  65. }catch (Exception e){
  66. logger.error("发生异常",e);
  67. throw new CustomException(ResultCode.LIMIT_NUMBER);
  68. }
  69. }
  70. }

自定义异常

  1. package com.example.common;
  2. /**
  3. * @method: $
  4. * @description: 描述一下方法的作用
  5. * @date: $
  6. * @author: myth
  7. * @return $
  8. */
  9. public class RequestLimitException extends Exception{
  10. private static final long serialVersionUID = 1364225358754654702L;
  11. public RequestLimitException(){
  12. super("1分钟内最多只能访问5次!");
  13. }
  14. public RequestLimitException(String message){
  15. super(message);
  16. }
  17. }

控制类中使用

  1. @PostMapping("/login")
  2. //1分钟内只允许访问5次,超过之后将会被禁止1分钟
  3. @RequestLimit(count=5,time=60000)
  4. public Result<Account> login(@RequestBody Account account, HttpServletRequest request) {
  5. if (StrUtil.isBlank(account.getName()) || StrUtil.isBlank(account.getPassword()) || account.getLevel() == null) {
  6. throw new CustomException(ResultCode.PARAM_LOST_ERROR);
  7. }
  8. }

总的来说,在选择具体的防刷手段时,需要根据系统的具体需求和场景来决定。例如,如果对性能要求较高,可以考虑使用基于内存的限流算法;如果需要更复杂的控制策略,可以使用专门的限流组件或API网关。同时,还需要考虑到系统的扩展性和维护性,选择最适合当前和未来需求的方案。

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/爱喝兽奶帝天荒/article/detail/874252
推荐阅读
相关标签
  

闽ICP备14008679号