频率单位(频率单位换算hz换s)

目标

相信大家都听过接口安全,接口限流等这些词语,那么本篇文章就是从最基本的问题开始,带大家手写一个控制接口单位时间内访问频率的demo。好了,下面开始上代码。

环境+依赖

spring boot工程就不在此搭建了,小编直接贴出核心依赖

 <dependency>
   <groupId>org.springframework.boot</groupId>
  <artifactId>spring-boot-starter-data-redis</artifactId>
  <version>2.3.0.RELEASE</version>
 </dependency>
 <dependency>
  <groupId>org.apache.commons</groupId>
  <artifactId>commons-pool2</artifactId>
  <version>2.4.2</version>
 </dependency>
 <dependency>
<groupId>org.springframework.boot</groupId>
   <artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
 <dependency>
  <groupId>org.springframework.boot</groupId>
  <artifactId>spring-boot-starter-web</artifactId>
</dependency>

里面有用到redis,具体的配置可以参考小编之前的文章springboot整合redis,此处不再单独列出来了。

自定义注解 + 拦截器

  • 自定义注解
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface ApiLimit {
    //time时间内请求的最大次数
    int count();

    //时间段内,单位:s
    int time();
}
  • 拦截器
public class ApiInterceptor implements HandlerInterceptor {

    @Autowired
    private RedisTemplate redisTemplate;

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        if(handler instanceof HandlerMethod) {
            HandlerMethod handlerMethod = (HandlerMethod) handler;
            Method method = handlerMethod.getMethod();
            ApiLimit apiLimit = method.getAnnotation(ApiLimit.class);
            if(!ObjectUtils.isEmpty(apiLimit)) {
                int count = apiLimit.count();
                int time = apiLimit.time();
                String ip = request.getRemoteAddr();
                String requestURI = request.getRequestURI();
                String redisKey = "apiKey_" + ip + "_" + requestURI;
                System.out.println("redisKey======>" + redisKey);
                if (ObjectUtils.isEmpty(redisTemplate.opsForValue().get(redisKey))) {
                    AtomicInteger atomicInteger = new AtomicInteger(1);
                    redisTemplate.opsForValue().set(redisKey, atomicInteger, time, TimeUnit.SECONDS);
                    System.out.println("当前访问次数:" + ((AtomicInteger) redisTemplate.opsForValue().get(redisKey)).get());
                } else {
                    AtomicInteger atomicInteger = (AtomicInteger) redisTemplate.opsForValue().get(redisKey);
                    if (atomicInteger.incrementAndGet() > count) {
                        throw new RuntimeException("访问太频繁了,请休息一会");
                    }
                    Long expire = redisTemplate.getExpire(redisKey, TimeUnit.SECONDS);
                    redisTemplate.opsForValue().set(redisKey, atomicInteger, expire ,TimeUnit.SECONDS);
                    System.out.println("当前访问次数:" + ((AtomicInteger) redisTemplate.opsForValue().get(redisKey)).get());
                }
            } else {
                return true;
            }
        }
        return true;
    }
}

ip的获取大家可以借鉴网上的工具,此处为测试就简写了。

  • 拦截器配置

拦截器写好之后,需要将它注册到spring中

@Configuration
public class WebMvcConfig implements WebMvcConfigurer {

    @Bean
    public ApiInterceptor apiInterceptor() {
        return new ApiInterceptor();
    }

    @Override
    public void addInterceptors(InterceptorRegistry registry) {
      	//这里我们添加了一个测试的路径
        registry.addInterceptor(apiInterceptor()).addPathPatterns("/test/limit");
    }
}

测试类

只需要在需要拦截的接口上加上@ApiLimit注解,定义好时间和访问次数即可。

@Controller
@RequestMapping("/test")
public class TestController {

    @GetMapping("/limit")
    @ResponseBody
    @ApiLimit(count = 5, time = 10)
    public String get() {
        return "hello world !!!";
    }
}

测试

我们先连续访问这个url,10s后再次访问。结果如下

手写一个注解实现接口单位时间内的访问频率的拦截器

连续访问

手写一个注解实现接口单位时间内的访问频率的拦截器

10s后再次访问

从测试结果可以看到,当我们10s连续访问这个接口超过5的话,直接抛出异常了。等10s后,再次访问,接口恢复如初。基本上满足了我们的小目标。

结尾

以上就是小编今天分享的内容了,喜欢小编的小伙伴可以关注小编。下篇文章小编将带领大家用spring boot整合开源项目来重新写一个接口限流的demo。好了,转发+评论+点赞 这篇文章,私信小编【接口限流】可获得源码。

本文来自盼夏投稿,不代表胡巴网立场,如若转载,请注明出处:https://www.hu85.com/180647.html

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 xxxxx@qq.com 举报,一经查实,本站将立刻删除。