一个注解搞定 SpringBoot 接口防刷,真香!

开发者福利!热门AI工具限时免费用 购周边即赠Coding Plan Lite,Claude Code、Cursor等20+工具畅享,效率翻倍! 阅读详情

大家好,我是猿人(猿码天地创始人),今天给大家聊聊接口防刷的那些事。

接口防刷,顾名思义,想让某个接口某个人在某段时间内只能请求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服务中,最后需要在接口上加上注解,设定好参数即可完成接口防刷功能,是不是很高大上。

扩展

在开发分布式高并发系统时有三把利器用来保护系统:缓存、降级、限流。

  • 缓存

缓存的目的是提升系统访问速度和增大系统处理容量。

  • 降级

降级是当服务出现问题或者影响到核心流程时,需要暂时屏蔽掉,待高峰或者问题解决后再打开。

  • 限流

限流的目的是通过对并发访问/请求进行限速,或者对一个时间窗口内的请求进行限速来保护系统,一旦达到限制速率则可以拒绝服务、排队或等待、降级等处理。

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

点赞&在看是最大的支持
SpringBoot + EasyExcel实战:多Sheet复杂表头数据导入导出全解析 本文详细解析了在SpringBoot项目中,如何使用EasyExcel高效处理多Sheet与复杂表头数据的导入导出。通过实战代码演示了如何读取不同结构的Sheet、合并数据,以及应对多级合并表头等复杂场景,并提供了性能优化与避坑指南,助力开发者应对企业级报表需求。 阅读详情

相关推荐

基于SpringBoot与Netty的JT808协议通信系统设计与实现

本文详细介绍了基于SpringBoot与Netty构建JT808协议通信系统的设计与实现。通过分析JT808协议核心结构,结合Netty高性能网络框架处理TCP粘包拆包、编解码及心跳机制,并利用SpringBoot快速集成业务生态,实现了一个稳定、可扩展的车联网终端与服务器通信解决方案。

weixin_29305313的博客 338

接口如何止被,教你有效的8种方法

现在越来越多的应用程序和服务都提供了API接口,使得开发人员可以方便地与这些应用程序和服务进行交互。但是,由于API接口是公开的,因此很容易被黑客利用,对系统造成损害。为了确保API接口的安全性,我们需要采取一些措施,例如使用签名机制和限流机制来增强接口的安全性。在本文中,我们将介绍如何使用PHP实现这些措施,并止API接口被恶意

m0_66326520的博客 4474

gtsam 学习十(ISAM2 理论)

翻译自:iSAM2: Incremental Smoothing and Mapping Using the Bayes Tree 摘要 提出了一种新型的贝斯树处理稀疏矩阵,在转化为因子图,可以更好的求解平方根信息和映射问题。 文中提出了三个概念 使用概率密度项进行矩阵分解 介绍如何将矩阵分解转换为贝叶斯数和条件概率密度 基于贝叶斯树提供了一种新的系数非线性优化:ISAM2(进行重新排序和重新线性化,避免了批量更新) 问题描述 文章聚焦与如何用增量实时解决非线性问题, 利用增量即新的测量值实时更新估

weixin_37781153的博客 8378

优雅的接口处理方式,看这一篇就够了(经典)

优雅的接口处理方式,看这一篇就够了

gb4215287的博客 929

如何接口

接口(即止恶意频繁访问接口)是构建稳定、安全的后端服务的关键环节。接口会带来以下问题:服务压力大 → 崩溃或变慢;资源被滥用 → 例如验证码短信费用增加;用户体验差 → 正常用户无法访问服务;安全隐患 → 存在撞库攻击、恶意爬虫等风险。

王景程的博客 2740

SpringBootSpring Boot 如何实现接口

SpringBoot接口

低调做人,低调编码,神码都是浮云 3098

如何止被恶意接口

在面试时,经常会被问一个问题:如何止别人恶意接口?这是一个非常有意思的问题,范措施挺多的。今天这篇文章专门跟大家一起聊聊,希望对你会有所帮助。

kangbin825的专栏 1056

爽!一个注解搞定 SpringBoot 操作日志

往期热门文章:1、公司这套架构统一处理 try...catch 真香! 2、消灭空指针,这才是Java 8的最优解? 3、阿里的又一款数据高效同步工具DataX,真香! 4、还在用分页?试试 MyBatis 流式查询,强的一批! 5、IDEA 28 个天花板技巧!文章来源:https://blog.csdn.net/weixin_43954303/article/details/113781801...

Java后端技术 352

动态线程池,真香

基于以上背景分析,我们对线程池 ThreadPoolExecutor 做一些扩展增强,主要实现以下目标」❝1.实现对运行中线程池参数的动态修改,实时生效2.实时监控线程池的运行状态,触发设置的报警策略时报警,报警信息推送办公平台3.定时采集线程池指标数据,配合像 grafana 这种可视化监控平台做大盘监控❞「经过多个版本的迭代,目前最新版本 v1.0.9 具有以下特性」✅「代码零侵入」:所有配置都放在配置中心,对业务代码零侵入「轻量简单」:基于 SpringBoot 实现,引入starter。

m0_69632475的博客 780

SpringBoot 挥别 spring.factories:老伙计退场,新方案真香

有了它,SpringBoot 启动时就能自动找到这些实现类,完成装配和扩展,这也是 SpringBoot “约定优于配置”的精髓所在——不用咱们手动写一堆配置,它自己就搞定了。其实它不是 SpringBoot 凭空造的,而是 Java SPI 机制的“变种选手”,说白了就是 SpringBoot 自动配置的“幕后推手”,没它,很多“开箱即用”的功能都玩不转。对咱们开发者来说,不用死记硬背迁移步骤,搞懂背后“适配新生态、提升效率”的逻辑,就能明白这场变革的意义,写代码也能更贴合框架的发展方向。

root 800

美团动态线程池,真香

大家好,我是宝哥!背景使用线程池 ThreadPoolExecutor 过程中你是否有以下痛点呢?1.代码中创建了一个 ThreadPoolExecutor,但是不知道那几个核心参数设置多少比较合适2.凭经验设置参数值,上线后发现需要调整,改代码重启服务,非常麻烦3.线程池相对开发人员来说是个黑盒,运行情况不能及时感知到,直到出现问题如果你有以上痛点,动态可监控线程池(DynamicTp)或许能帮...

程序员闪充宝 333

<span class=“js_title_inner“>SpringBoot 挥别 spring.factories:老伙计退场,新方案真香!</span>

有了它,SpringBoot 启动时就能自动找到这些实现类,完成装配和扩展,这也是 SpringBoot “约定优于配置”的精髓所在——不用咱们手动写一堆配置,它自己就搞定了。其实它不是 SpringBoot 凭空造的,而是 Java SPI 机制的“变种选手”,说白了就是 SpringBoot 自动配置的“幕后推手”,没它,很多“开箱即用”的功能都玩不转。对咱们开发者来说,不用死记硬背迁移步骤,搞懂背后“适配新生态、提升效率”的逻辑,就能明白这场变革的意义,写代码也能更贴合框架的发展方向。

root 1028

最新 Spring 系列教程,都在这了!

Java技术栈www.javastack.cn优秀的Java技术公众号以下是Java技术栈微信公众号发布的关于 Spring/ Spring MVC/ Spring Boot/ Spri...

Java技术栈,分享最主流的Java技术 699

最新 Spring 系列教程,共 99+ 篇,建议收藏~

以上是字节二面的一些问题,面完之后其实挺后悔的,没有提前把各个知识点都复习到位。(img-Ucf7Nkr2-1713731276189)](img-DSlbcXLt-1713731276189)]MySQL+Redis学习笔记算法+JVM+JAVA核心知识整理。MySQL+Redis学习笔记算法+JVM+JAVA核心知识整理。MySQL+Redis学习笔记算法+JVM+JAVA核心知识整理。MySQL+Redis学习笔记算法+JVM+JAVA核心知识整理。,现在起闭关修炼半个月,争取早日上岸!

Z70czd的博客 902

为什么 Spring和IDEA 都不推荐使用 @Autowired 注解

往期热门文章:1、从阿里跳槽来的工程师,写个Controller都这么优雅! 2、try catch真的会影响性能?居然被骗了好几年... 3、学会这10种定时任务,我有点飘了 4、大家注意了,JavaBean转Map有一个巨坑千万小心! 5、别再用currentTimeMillis统计耗时了,太 Low,试试StopWatch吧!大家在使用IDEA开发的时候有没有注意到过一个提示,在字段上使用S...

Java后端技术 287

2026年Java面试题

springboot项目打包:你的项目还是打成一个xx.jar包吗?换掉SpringBoot?解放双手:SpringBoot 公共字段自动填充的6种神技,开发效率飙升!SpringBoot+轻量级分布式日志框架GrayLog!SpringBoot 快速开发神器发布,10 倍提升开发效率!Spring Boot性能提升的核武器,速度提升500%!SpringBoot 中的自带工具类,开发效率增加一倍!Java + LangChain 开发大语言模型应用!Spring Boot 3.4 正式发布,王炸级更新!

lxw1844912514的博客 383
上一篇: 跟着猿人学Java-001-八大基本数据类型
下一篇: SpringBoot 接口幂等性的实现方案
猿码天地
博客等级 码龄11年 3407粉丝 132原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

猿码天地

相互学习,谢谢您的打赏。

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值