大家好,我是猿人(猿码天地创始人),今天给大家聊聊接口防刷的那些事。
接口防刷,顾名思义,想让某个接口某个人在某段时间内只能请求N次,或者某个接口对外在某一段时间内只允许访问N次。在项目中比较常见的问题也有,那就是连点按钮导致请求多次,以前在web端有表单重复提交,可以通过token 来解决。除了上面的方法外,前后端配合的方法。现在全部由后端来控制。
我是「猿码天地」,一个热爱技术、热爱编程的IT猿。技术是开源的,知识是共享的!
写作是对自己学习的总结和记录,如果您对 Java、分布式、微服务、中间件、Spring Boot、Spring Cloud等技术感兴趣,可以关注我的动态,我们一起学习,一起成长!
用知识改变命运,让家人过上更好的生活,互联网人一家亲!

Java知识学堂:https://gitee.com/zhangbw666/it-knowledge
好,废话不多说,直接干,进入正题:Good Good Study,Day Day Up!
技术要求:SpringBoot相关技术、Redis相关技术。
API 接口防刷原理
-
在你请求的时候,服务器通过redis 记录下你请求的次数,如果次数超过限制就不给访问。
-
在redis 保存的key 是有时效性的,过期就会删除。
好,我们直接用代码来实现接口防刷,猿人已运用到实际项目中,感觉还是挺香的,特地分享出来!
注解类
-
首先定义一个注解类,包含失效时间 单位(秒)、最大请求次数、是否需要登录三个属性。
/**
* <h3>fas-cbs</h3>
* <p>接口防刷注解类</p>
* @author : zhang.bw
* @date : 2021-03-08 16:07
**/
@Retention(RUNTIME)
@Target(METHOD)
public @interface AccessLimit {
// 失效时间 单位(秒)
int seconds();
// 最大请求次数
int maxCount();
// 是否需要登录
boolean needLogin()default true;
}
实现拦截器
-
定义好注解类后,需要在Interceptor拦截器中实现具体逻辑。
/**
* <h3>fas-cbs</h3>
* <p>在Interceptor拦截器中实现</p>
* @author : zhang.bw
* @date : 2021-03-08 16:24
**/
@Component
public class LimitInterceptor extends HandlerInterceptorAdapter {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
//判断请求是否属于方法的请求
if(handler instanceof HandlerMethod){
HandlerMethod hm = (HandlerMethod) handler;
//获取方法中的注解,看是否有该注解
AccessLimit accessLimit = hm.getMethodAnnotation(AccessLimit.class);
if(accessLimit == null){
return true;
}
int seconds = accessLimit.seconds(); // 失效时间 单位(秒)
int maxCount = accessLimit.maxCount(); // 最大请求次数
boolean login = accessLimit.needLogin(); // 是否需要登录
String key = request.getRequestURI();
//如果需要登录
if(login){
//获取登录的session进行判断
UserInfo systemUser = SystemUserUtil.getSystemUser(request);
String userNo = systemUser.getUserNo();
key+=""+userNo;
}
Integer count = 0;
//从redis中获取用户访问的次数
if(RedisUtil.get(key) != null){
count = (Integer) RedisUtil.get(key);
}
if(count == 0){
//第一次访问
RedisUtil.set(key,1);
RedisUtil.expire(key,seconds); //置缓存失效时间(单位:秒)
}else if(count < maxCount){
//加1
RedisUtil.incr(key,1);
}else{
//超出访问次数
render(response, "接口请求次数超过设定值");
return false;
}
}
return true;
}
/**
* 封装返回值
* @param response
* @param msg
* @throws Exception
*/
private void render(HttpServletResponse response, String msg)throws Exception {
response.setContentType("application/json;charset=UTF-8");
OutputStream out = response.getOutputStream();
out.write(msg.getBytes("UTF-8"));
out.flush();
out.close();
}
}
注册服务
-
然后将拦截器注册到SpringBoot服务中。
@Configuration
public class WebConfig extends WebMvcConfigurerAdapter {
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(new LimitInterceptor());
}
}
Controller加注解
-
接着在Controller中加入注解@AccessLimit(seconds=5, maxCount=5000, needLogin=false),其中seconds、maxCount、needLogin值根据具体业务赋值。
-
OA请款接口注解(@AccessLimit(seconds=5, maxCount=5000, needLogin=false)):表示5秒内允许请求接口5000次,needLogin为false表示不需要登录获取session值,直接调接口即可。
-
登录接口注解(@AccessLimit(seconds=10, maxCount=1000, needLogin=false)),表示10秒内允许1000人登录。
@ApiOperation(value = "OA请款接口", notes = "OA请款接口")
@AccessLimit(seconds=5, maxCount=5000, needLogin=false)
@RequestMapping(value = REQUSET_MODEL + "/oAPayment", method = RequestMethod.POST)
public CbsResult<CbsOAPayInfo> oAPayment(@Valid @RequestBody CbsOAPaymentRequest request)throws Exception{
return cbsOAPayInfoService.syncOAPayment(request);
}
@ApiOperation(value = "登录", notes = "登录")
@AccessLimit(seconds=10, maxCount=1000, needLogin=false)
@RequestMapping(value = "/user/login", method = RequestMethod.POST)
public CbsResult<UserInfo> login(@RequestBody UserLogin userLogin, HttpServletRequest request) {
if(userLogin.getUsername() == null) {
log.info("[点击菜单]从OA获取员工工号为空,忽略此日志......");
return null;
}
UserInfo userInfo = null;
HttpSendUtil.login(request,userLogin,userInfo);
return new CbsResult<UserInfo>(userInfo);
}
好,通过自定义注解类、拦截器实现、将拦截器注册到SpringBoot服务中,最后需要在接口上加上注解,设定好参数即可完成接口防刷功能,是不是很高大上。
扩展
在开发分布式高并发系统时有三把利器用来保护系统:缓存、降级、限流。
-
缓存
缓存的目的是提升系统访问速度和增大系统处理容量。
-
降级
降级是当服务出现问题或者影响到核心流程时,需要暂时屏蔽掉,待高峰或者问题解决后再打开。
-
限流
限流的目的是通过对并发访问/请求进行限速,或者对一个时间窗口内的请求进行限速来保护系统,一旦达到限制速率则可以拒绝服务、排队或等待、降级等处理。

你多学一样本事,就少说一句求人的话,现在的努力,是为了以后的不求别人,实力是最强的底气。记住,活着不是靠泪水博得同情,而是靠汗水赢得掌声。——《写给程序员朋友》
点赞&在看是最大的支持
338




被折叠的 条评论
为什么被折叠?



