首页 > 数据库 >SpringBoot+Redis+自定义注解实现接口防刷(限制不同接口单位时间内最大请求次数)

SpringBoot+Redis+自定义注解实现接口防刷(限制不同接口单位时间内最大请求次数)

时间:2023-05-10 10:14:50浏览次数:56  
标签:防刷 请求 自定义 接口 springframework key org import annotation

场景

SpringBoot搭建的项目需要对开放的接口进行防刷限制,不同接口指定多少秒内可以请求指定次数。

比如下方限制接口一秒内最多请求一次。

 

注:

博客:
https://blog.csdn.net/badao_liumang_qizhi

实现

1、实现思路

首先自定义注解,添加时间区间和最大请求次数字段。

然后自定义拦截器拦截方法上面是否有自定义的注解,如果有则获取请求的url,并作为redis中存储的key,区间区间即作为redis

的key的过期时间,每次请求累加次数并存储到redis中,判断在redis的key有效期内超过最大请求次数,则返回请求频繁的响应。

2、首先自定义注解实现

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface AccessLimit {
    /**
     * 秒数时间区间(多少秒内)
     * @return
     */
    int seconds();
    /**
     * 最大请求次数
     * @return
     */
    int maxCount();
}

3、然后自定义拦截实现HandlerInterceptor接口,并重写其preHandle方法,实现方法请求前的拦截

import com.alibaba.fastjson.JSON;
import com.badao.demo.common.AjaxResult;
import com.badao.demo.constant.Constants;
import com.badao.demo.utils.RedisCache;
import org.springframework.beans.factory.annotation.Autowired;
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.OutputStream;
import java.util.concurrent.TimeUnit;

@Component
public class FangshuaInterceptor implements HandlerInterceptor {

    @Autowired
    private RedisCache redisService;

    @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();
            //获取请求的Url作为redis中存储的key
            String key = request.getRequestURI();
            //从redis中获取用户访问的次数
            Integer count = redisService.getCacheObject(key);
            if(count == null){
                //第一次访问
                redisService.setCacheObject(key,1,seconds, TimeUnit.SECONDS);
            }else if(count < maxCount){
                //加1
                count+=1;
                redisService.setCacheObject(key,count,seconds, TimeUnit.SECONDS);
            }else{
                //超出访问次数,则渲染响应结果
                render(response);
                return false;
            }
        }
        return true;
    }

    /**
     * 接口渲染
     * @param response
     * @throws Exception
     */
    private void render(HttpServletResponse response)throws Exception {
        response.setContentType("application/json;charset=UTF-8");
        OutputStream out = response.getOutputStream();
        String str  = JSON.toJSONString(AjaxResult.error(Constants.CALL_TOO_OFEN));
        out.write(str.getBytes("UTF-8"));
        out.flush();
        out.close();
    }
}

其中RedisCache是封装的操作redis的工具类

AjaxResult是封装的响应结果实体。

Constants.CALL_TOO_OFEN是常量类用来提示请求太频繁。

以上工具类的封装可以参考

若依前后端分离版手把手教你本地搭建环境并运行项目:

https://blog.csdn.net/BADAO_LIUMANG_QIZHI/article/details/108465662

4、然后将intercepter注册到springboot中

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;

/**
 * 把intercepror 注册到springboot中
 */
@Configuration
public class WebConfig implements WebMvcConfigurer {

    @Autowired
    private FangshuaInterceptor interceptor;

    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(interceptor);
    }
}

5、使用时在接口方法上添加注解并指定时间和最大请求次数

    @AccessLimit(seconds = 1,maxCount = 1)
    @GetMapping("/test")
    public AjaxResult test(@RequestParam("mineApiCode") String mineApiCode)

上面参数设置就是1秒内最大请求次数为1次。

标签:防刷,请求,自定义,接口,springframework,key,org,import,annotation
From: https://www.cnblogs.com/badaoliumangqizhi/p/17387132.html

相关文章

  • 实验五 通用接口数据库编程
    实验五通用接口数据库编程第1关:JDBC查询数据packagestep1;importjava.sql.\*;publicclassQuery{publicstaticvoidqueryDB(){//声明变量Connectionconn=null;Statementstat=null;ResultSetrs=null;/\*\*\*\*\*\*\*\*\*查询出的数据保存在这......
  • php获取未解码之前的原始接口请求参数
    前言目前的几个项目,业务方基本都使用POST方式请求接口,我们本机磁盘会保留一份请求的原始参数用于请求分析和问题排查使用,一般有问题,也会基于seqid(请求唯一id)捞到日志,copy参数模拟请求看是否复现,但一直有个比较蛋疼的问题,PHP的$_POST,$_GET,$_REQUEST这些获取参数的方法获取到的......
  • 微信小程序 自定义组件 监听数据变化 出现异常 Maximum call stack size exceeded.
    代码调用处: 组件内部  本地调试无异常,发布之后出现此异常解决方法:监听属性steps的值变化时,调用处不能使用双向绑定,去掉steps的双向绑定即可,具体的原因未知(不知为啥本地调试不会抛异常) ......
  • php获取1688阿里巴巴关键字搜索新品数据API接口、获取上新关键词推荐、获取宝贝详情数
    ​ php的主要优势以及特点: 便于学习和使用:PHP是一门非常容易学习和使用的语言,其语法和结构都非常简单。具有广泛的应用范围:PHP可以用于开发各种类型的Web应用,如博客系统、内容管理系统、电子商务网站、社交网络等。巨大的社区支持:有一个庞大的PHP社区,提供了大量的......
  • 【asp.net core】自定义模型绑定及其验证
    引言水此篇博客,依旧是来自群里的讨论,最后说到了,在方法参数自定义了一个特性,用来绑定模型,优先从Form取,如果为空,或者不存在,在从QueryString中获取并且绑定,然后闲着无聊,就水一篇博客,如果大家有什么需求或者问题,可以找我,很高兴能为你们带来帮助。IModelBinderFactory......
  • mybatis 自定义序列号
    功能需求:每天的序列号从1开始,保留四位数,不足4位往前补01,新建一张表 CREATETABLE`sequence`(`day_id`dateDEFAULTNULLCOMMENT'账期',`name`varchar(50)COLLATEutf8mb4_binNOTNULLCOMMENT'序列的名字',`current_value`int(11)NOTNULLCOMMENT'序列......
  • Spring Boot项目对接腾讯云COS对象存储上传文件接口
    SpringBoot项目对接腾讯云COS对象存储上传文件接口pom.xml<dependency><groupId>com.qcloud</groupId><artifactId>cos_api</artifactId><version>5.6.35</version></dependency>application.ymlcos:secretId:xxx......
  • 河北稳控科技多通道振弦传感器采集仪VTN416P(H)接口定义
    河北稳控科技多通道振弦传感器采集仪VTN416P(H)接口定义 端子定义记忆口诀:不管什么功能的端子,右侧均是负。所以,传感器端子最右两个是频率正负,电源端子从左往右是正负,不需要考虑端子在上侧还是下侧不管怎么处理、谁在现场检查,不需要看手册,只记住一句话就行,“右侧是负”,见下图。......
  • C#自定义异常就这么简单
    C#是一种强类型语言,可以捕获和处理各种异常,从而帮助我们发现程序中出现的错误。在程序开发过程中,如果需要找到特定的错误情况并处理,这时就需要创建自定义异常。本文将介绍如何在C#中创建和使用自定义异常。1、什么是异常?异常是指在程序执行期间发生的错误或异常情况,例如除法中除......
  • C/C++常用接口实现【持续更新】
    目录判断大小端判断大小端一般方法boolIsSmallEndian(){intnum=1;char*p=(char*)&num;if(*p==1){printf("小端\n");returntrue;}returnfalse;}unionboolIsSmallEndian(){unionUn{char......