Spring Boot如何利用拦截器加缓存完成接口防刷操作

网友投稿 1189 2022-10-30

Spring Boot如何利用-加缓存完成接口防刷操作

Spring Boot如何利用-加缓存完成接口防刷操作

目录为什么需要接口防刷技术解析主要代码测试结果总结

为什么需要接口防刷

为了减缓服务器压力,将服务器资源留待给有价值的请求,防止恶意访问,一般的程序都会有接口防刷设置,接下来介绍一种简单灵活的接口防刷操作

技术解析

主要采用的技术还是拦截+缓存,我们可以通过自定义注解,将需要防刷的接口给标记出来管理,利用缓存统计指定时间区间里,具体的某个ip访问某个接口的频率,如果超过某个阈值,就让他进一会儿小黑屋,到期自动解放

主要代码

前置环境搭建,Spring Boot项目,引入Web和Redis依赖

org.springframework.boot

spring-boot-starter-parent

2.3.3.RELEASE

org.springframework.boot

spring-boot-starter-web

org.springframework.boot

spring-boot-starter-data-redis

org.springframework.boot

spring-boot-starter

自定义注解

定义-,重写preHandler方法

@Override

public boolean preHandle(HttpServletRequest request ,HttpServletResponse response ,Object handler) throws Exception {

log.info("------------接口防刷----------------");

if (handler instanceof HandlerMethod) {

HandlerMethod handlerMethod = (HandlerMethod) handler;

AccessLimit accessLimit = handlerMethod.getMethodAnnotation(AccessLimit.class);

// 如果没有该注解,则不在防刷目标里,直接返回

if (accessLimit == null) {

return true;

}

// 获取最大访问次数

int maxAccessCnt = accessLimit.maxAccessCnt();

// 获取ip

String key = getRealIp(request);

// ip+请求的接口路径 => 唯一标识key

key += request.getRequestURI();

//当前访问次数

Object value = redisTemplate.opsForValue().get(key);

if (value == null) {

//第一次访问 设置key保留时长为1s

redisTemplate.opsForValue().set(key, 1, 1L, TimeUnit.SECONDS);

} else {

Integer currentCnt = (Integer) value;

if (currentCnt < maxAccessCnt) {

//对应key值自增

redisTemplate.opsForValue().increment(key);

} else {

//超出接口时间段内允许访问的次数,直接返回错误信息,同时设置过期时间 20s自动剔除

redisTemplate.expire(key, 20L,TimeUnit.SECONDS);

response.setContentType("application/json;charset=utf-8");

try {

OutputStream out = response.getOutputStream();

out.write("访问次数已达上线!请稍后再访问".getBytes(StandardCharsets.UTF_8));

out.flush();

out.close();

} catch (IOException e) {

e.printStackTrace();

}

return false;

}

}

}

return true;

}

添加到需要防刷的接口上

/**

* 返回不携带data的(成功例子)

* @return

*/

@AccessLimit

@GetMapping("/getPaperS")

public ApiResult getPaperInfoSucceuXDvxqvPss() {

if (log.isInfoEnabled()) {

log.info("收到获取paper信息请求...");

}

//...业务逻辑

if (log.isInfoEnabled()) {

log.info("完成获取paper信息请求,准备返回对象信息");

}

return ApiResultGenerator.success();

}

测试结果

正常情况下

到底时间段内最大访问次数时

总结

版权声明:本文内容由网络用户投稿,版权归原作者所有,本站不拥有其著作权,亦不承担相应法律责任。如果您发现本站中有涉嫌抄袭或描述失实的内容,请联系我们jiasou666@gmail.com 处理,核实后本网站将在24小时内删除侵权内容。

上一篇:基于fis3和vue全家桶,搭建前端工程化脚手架
下一篇:MyBatis从入门到精通—源码剖析之二级缓存细节
相关文章

 发表评论

暂时没有评论,来抢沙发吧~