排名好的宜昌网站建设,学校校园网站 资源建设方案,如何做 旅游网站内容,wordpress扁平化博客主题一、API接口防刷
顾名思义#xff0c;想让某个接口某个人在某段时间内只能请求N次。
二、原理
在请求的时候#xff0c;服务器通过Redis记录你请求的次数#xff0c;如果次数超过限制就不给访问。 在redis保存的key是有失效的#xff0c;过期就会删除。
三、api限流的场…一、API接口防刷
顾名思义想让某个接口某个人在某段时间内只能请求N次。
二、原理
在请求的时候服务器通过Redis记录你请求的次数如果次数超过限制就不给访问。 在redis保存的key是有失效的过期就会删除。
三、api限流的场景
限流的需求出现在许多常见的场景中
秒杀活动有人使用软件恶意刷单抢货需要限流防止机器参与活动某api被各式各样系统广泛调用严重消耗网络、内存等资源需要合理限流淘宝获取ip所在城市接口、微信公众号识别微信用户等开发接口免费提供给用户时需要限流更具有实时性和准确性的接口需要付费。
四、api限流代码实现
使用自定义注解的方式实现
1.添加依赖
dependencygroupIdorg.springframework.boot/groupIdartifactIdspring-boot-starter-web/artifactId
/dependency
dependencygroupIdorg.springframework.cloud/groupIdartifactIdspring-cloud-starter-bootstrap/artifactIdversion3.1.5/version
/dependency
!--nacos 服务注册中心--
dependencygroupIdcom.alibaba.cloud/groupIdartifactIdspring-cloud-starter-alibaba-nacos-discovery/artifactIdversion2021.1/version
/dependency
!--nacos 配置中心--
dependencygroupIdcom.alibaba.cloud/groupIdartifactIdspring-cloud-starter-alibaba-nacos-config/artifactIdversion2021.1/version
/dependency
!--redis 依赖--
dependencygroupIdorg.springframework.boot/groupIdartifactIdspring-boot-starter-data-redis/artifactId
/dependency2.添加自定义AccessLimit注解
package com.example.demo.aop;import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;/*** 自定义接口api接口限流* author qzz* date 2024/1/11*/
Retention(RetentionPolicy.RUNTIME)
Target(ElementType.METHOD)
public interface AccessLimit {/*** 时间间隔单位秒* return*/int seconds() default 60;/*** 最大访问次数* return*/int maxCount() default 60;/*** 是否需要登录* return*/boolean needLogin() default true;
}
3.添加AccessLimitIntercepter拦截器
自定义一个拦截器请求之前进行请求次数校验
package com.example.demo.intercepter;import com.alibaba.fastjson.JSON;
import com.example.demo.aop.AccessLimit;
import com.example.demo.enums.CodeMsg;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.HandlerInterceptor;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.OutputStream;
import java.lang.reflect.Method;
import java.nio.charset.StandardCharsets;
import java.util.concurrent.TimeUnit;/*** 限制访问拦截器* author qzz* date 2024/1/12*/
Slf4j
Component
public class AccessLimitIntercepter implements HandlerInterceptor {private RedisTemplateString,Object redisTemplate;Autowiredpublic AccessLimitIntercepter(RedisTemplateString,Object redisTemplate){this.redisTemplate redisTemplate;}Overridepublic boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {//方法请求拦截 Handler 是否为 HandlerMethod 实例if(handler instanceof HandlerMethod){HandlerMethod hm (HandlerMethod) handler;// 获取方法Method method hm.getMethod();// 是否有AccessLimit注解if (!method.isAnnotationPresent(AccessLimit.class)) {return true;}//获取方法中的AccessLimit注解AccessLimit accessLimit hm.getMethodAnnotation(AccessLimit.class);if(accessLimit null){return true;}int seconds accessLimit.seconds();int maxCount accessLimit.maxCount();boolean needLogin accessLimit.needLogin();String keyrequest.getRequestURI();//判断是否登录if(needLogin){//获取登录的session进行判断//...//获取用户idLong userId 1L;keyuserId;}//从redis中获取用户访问的次数Object count redisTemplate.opsForValue().get(key);log.info(count:{},count);if(count null){//第一次访问redisTemplate.opsForValue().set(key,1, Long.valueOf(String.valueOf(seconds)), TimeUnit.SECONDS);log.info(--------------------------第一次访问--------------------------);}else if(count!null Integer.valueOf(String.valueOf(count)) maxCount){//次数自增redisTemplate.opsForValue().increment(key,1);log.info(--------------------------次数自增--------------------------);}else{//超出访问次数render(response, CodeMsg.ACCESS_LIMIT_REACHED);return false;}}return true;}private void render(HttpServletResponse response, CodeMsg codeMsg) throws IOException {response.setContentType(application/json;charsetUTF-8);OutputStream outputStream response.getOutputStream();String str JSON.toJSONString(codeMsg);outputStream.write(str.getBytes(StandardCharsets.UTF_8));outputStream.flush();outputStream.close();}
}
拦截器写好了但是还得添加注册
4.WebConfig配置类
如果是Springboot的版本是2.*只需要实现WebMvcConfigurer然后重写addInterceptors()方法添加自定义拦截器即可。
如果是Springboot的版本是1.*只需要实现WebMvcConfigurerAdapter然后重写addInterceptors()方法添加自定义拦截器即可。
我的版本是2.4.6所以代码如下
package com.example.demo.config;import com.example.demo.intercepter.AccessLimitIntercepter;
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;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;/*** author qzz* date 2024/1/12*/
Configuration
public class WebConfig implements WebMvcConfigurer {Autowiredprivate AccessLimitIntercepter accessLimitIntercepter;Overridepublic void addInterceptors(InterceptorRegistry registry) {//添加拦截器registry.addInterceptor(accessLimitIntercepter);}
}5.controller控制层测试接口
使用方式在方法上使用注解AccessLimit(seconds 5, maxCount 5, needLogin true)
默认5秒内每个接口只能请求5次
package com.example.demo.controller;import com.example.demo.aop.AccessLimit;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;/*** 拦截器注册* author qzz* date 2024/1/11*/
RestController
public class TestController {AccessLimit(seconds 5, maxCount 5, needLogin true)RequestMapping(test/api/limit)public String testApiLimit(){return test api limit;}
}
五、完整代码
代码点击此处下载