java sringboot 限制接口外部访问频率 每秒钟接口访问次数不得超过1次

在Spring Boot中,可以通过AOP和Redis实现接口访问频率限制,限制每秒钟接口访问次数不得超过1次的方法如下:

引入Redis依赖
在pom.xml文件中添加Redis依赖:

xml

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>

配置Redis
在application.properties文件中配置Redis连接信息:

properties

spring.redis.host=127.0.0.1
spring.redis.port=6379
spring.redis.password=
spring.redis.database=0

编写AOP切面
创建一个切面类,用于限制接口的访问频率。在这个切面类中,我们需要使用Redis存储访问次数和时间戳,并根据设定的时间间隔和最大访问次数限制接口的访问频率。

import java.util.concurrent.TimeUnit;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
@Aspect
@Component
public class RequestLimitAspect {
    private static final int SECOND = 1;
    private static final int MAX_COUNT = 1;
    @Autowired
    private RedisTemplate<String, String> redisTemplate;
    @Pointcut("@annotation(com.example.demo.annotation.RequestLimit)")
    public void requestLimit() {
    }
    @Around("requestLimit()")
    public Object around(ProceedingJoinPoint joinPoint) throws Throwable {
        ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        HttpServletRequest request = attributes.getRequest();
        HttpServletResponse response = attributes.getResponse();
        String ip = request.getRemoteAddr();
        String uri = request.getRequestURI();
        String key = "req_limit:" + ip + ":" + uri;
        String countStr = redisTemplate.opsForValue().get(key);
        if (countStr == null) {
            redisTemplate.opsForValue().set(key, "1", SECOND, TimeUnit.SECONDS);
        } else {
            int count = Integer.parseInt(countStr);
            if (count >= MAX_COUNT) {
                response.setStatus(429);
                return "Too many requests";
            }
            redisTemplate.opsForValue().set(key, String.valueOf(count + 1), SECOND, TimeUnit.SECONDS);
        }
        return joinPoint.proceed();
    }
}

在上述代码中,我们首先使用@Autowired注解注入了RedisTemplate对象,该对象用于访问Redis数据库。然后,我们使用@Pointcut注解定义了一个切点requestLimit(),该切点表示被@RequestLimit注解标记的方法。接着,我们使用@Around注解定义了一个环绕通知,在被切入的方法执行前后执行该通知。在该通知中,我们首先获取请求的IP地址和URI,然后根据这些信息构建Redis的key值。如果该key值不存在,则将访问次数设置为1,并设置过期时间为1秒钟。如果该key值存在,则获取访问次数,如果访问次数超过1次,则返回429状态码和提示信息。否则,将访问次数加1,并将其存储到Redis中。
4. 添加自定义注解
创建一个自定义注解@RequestLimit,用于标记需要限制访问频率的方法:

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface RequestLimit {
}

在接口方法上添加注解
在需要限制访问频率的接口方法上添加@RequestLimit注解:

@RestController
public class HelloController {
    @RequestLimit
    @GetMapping("/hello")
    public String hello() {
        return "Hello, World!";
    }
}

在以上实现中,我们使用AOP和Redis实现了每秒钟接口访问次数不得超过1次的接口访问频率限制。具体实现可以根据实际需求进行调整。需要注意的是,以上代码可能会抛出Throwable异常,需要进行处理或抛出。

  • 1
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
可以通过使用拦截器或者过滤器实现对指定接口访问次数限制。 以下是使用拦截器实现限制访问次数的示例代码: 1. 创建自定义注解 `@AccessLimit`,用于标记需要限制访问次数接口。 ```java @Target(ElementType.METHOD) @Retention(RetentionPolicy.RUNTIME) public @interface AccessLimit { // 默认访问次数限制为5 int limit() default 5; // 时间段,单位为秒,默认为60秒 int seconds() default 60; } ``` 2. 创建拦截器 `AccessLimitInterceptor`,用于实现限制访问次数的逻辑。 ```java @Component public class AccessLimitInterceptor implements HandlerInterceptor { @Autowired private RedisTemplate<String, Object> redisTemplate; @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { // 判断是否标注了@AccessLimit注解 if (handler instanceof HandlerMethod) { HandlerMethod handlerMethod = (HandlerMethod) handler; if (!handlerMethod.hasMethodAnnotation(AccessLimit.class)) { return true; } // 获取@AccessLimit注解 AccessLimit accessLimit = handlerMethod.getMethodAnnotation(AccessLimit.class); // 获取接口访问限制次数和时间段 int limit = accessLimit.limit(); int seconds = accessLimit.seconds(); // 获取请求的IP地址和接口地址 String ipAddr = getIpAddress(request); String requestUrl = request.getRequestURI(); // 设置Redis中的Key String redisKey = String.format("%s_%s", ipAddr, requestUrl); // 判断Redis中是否存在Key ValueOperations<String, Object> valueOps = redisTemplate.opsForValue(); if (!redisTemplate.hasKey(redisKey)) { // 第一访问,设置初始值 valueOps.set(redisKey, 1, seconds, TimeUnit.SECONDS); } else { // 已经访问过,进行访问次数限制判断 int count = (int) valueOps.get(redisKey); if (count >= limit) { // 超出访问次数限制,返回错误信息 response.setContentType("application/json;charset=UTF-8"); response.getWriter().write("超出访问次数限制"); return false; } else { // 访问次数加1 valueOps.increment(redisKey, 1); } } } return true; } /** * 获取请求的IP地址 */ private String getIpAddress(HttpServletRequest request) { String ipAddr = request.getHeader("x-forwarded-for"); if (StringUtils.isBlank(ipAddr) || "unknown".equalsIgnoreCase(ipAddr)) { ipAddr = request.getHeader("Proxy-Client-IP"); } if (StringUtils.isBlank(ipAddr) || "unknown".equalsIgnoreCase(ipAddr)) { ipAddr = request.getHeader("WL-Proxy-Client-IP"); } if (StringUtils.isBlank(ipAddr) || "unknown".equalsIgnoreCase(ipAddr)) { ipAddr = request.getRemoteAddr(); } return ipAddr; } } ``` 3. 在需要限制访问次数接口上添加 `@AccessLimit` 注解。 ```java @RestController public class DemoController { @GetMapping("/demo") @AccessLimit public String demo() { return "Hello World!"; } } ``` 这样,每个IP地址在60秒内最多只能访问 `/demo` 接口5。 注意:以上代码仅供参考,实际应用中还需要考虑并发访问、线程安全等问题。
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值