API 接口防刷
2021-06-04 14:03
标签:防刷 一点 局部变量 sign 标记 ops value var boot @RequestLimit 注解 RequestLimitIntercept 拦截器 拦截器写好了,但是还得添加注册 WebMvcConfig 配置类 Controller 第一种:直接在类上使用注解@RequestLimit(maxCount = 5,second = 1) 第二种:在方法上使用注解@RequestLimit(maxCount = 5,second = 1) maxCount 最大的请求数、second 代表时间,单位是秒 默认1秒内,每个接口只能请求一次 如果在类和方法上同时有@RequestLimit注解 ,以方法上的参数为准,好像注释有点多了。 API 接口防刷 标签:防刷 一点 局部变量 sign 标记 ops value var boot 原文地址:https://blog.51cto.com/13981400/2393248
顾名思义,想让某个接口某个人在某段时间内只能请求N次。
在项目中比较常见的问题也有,那就是连点按钮导致请求多次,以前在web端有表单重复提交,可以通过token 来解决。
除了上面的方法外,前后端配合的方法。现在全部由后端来控制。
原理
在你请求的时候,服务器通过redis 记录下你请求的次数,如果次数超过限制就不给访问。
在redis 保存的key 是有时效性的,过期就会删除。
代码实现:
为了让它看起来逼格高一点,所以以自定义注解的方式实现
import java.lang.annotation.*;
/**
* 请求限制的自定义注解
*
* @Target 注解可修饰的对象范围,ElementType.METHOD 作用于方法,ElementType.TYPE 作用于类
* (ElementType)取值有:
* 1.CONSTRUCTOR:用于描述构造器
* 2.FIELD:用于描述域
* 3.LOCAL_VARIABLE:用于描述局部变量
* 4.METHOD:用于描述方法
* 5.PACKAGE:用于描述包
* 6.PARAMETER:用于描述参数
* 7.TYPE:用于描述类、接口(包括注解类型) 或enum声明
* @Retention定义了该Annotation被保留的时间长短:某些Annotation仅出现在源代码中,而被编译器丢弃;
* 而另一些却被编译在class文件中;编译在class文件中的Annotation可能会被虚拟机忽略,
* 而另一些在class被装载时将被读取(请注意并不影响class的执行,因为Annotation与class在使用上是被分离的)。
* 使用这个meta-Annotation可以对 Annotation的“生命周期”限制。
* (RetentionPoicy)取值有:
* 1.SOURCE:在源文件中有效(即源文件保留)
* 2.CLASS:在class文件中有效(即class保留)
* 3.RUNTIME:在运行时有效(即运行时保留)
*
* @Inherited
* 元注解是一个标记注解,@Inherited阐述了某个被标注的类型是被继承的。
* 如果一个使用了@Inherited修饰的annotation类型被用于一个class,则这个annotation将被用于该class的子类。
*/
@Documented
@Inherited
@Target({ElementType.METHOD,ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface RequestLimit {
// 在 second 秒内,最大只能请求 maxCount 次
int second() default 1;
int maxCount() default 1;
}
自定义一个拦截器,请求之前,进行请求次数校验import com.alibaba.fastjson.JSONObject;
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.handler.HandlerInterceptorAdapter;
import top.lrshuai.limit.annotation.RequestLimit;
import top.lrshuai.limit.common.ApiResultEnum;
import top.lrshuai.limit.common.Result;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;
import java.lang.reflect.Method;
import java.util.concurrent.TimeUnit;
/**
* 请求拦截
*/
@Slf4j
@Component
public class RequestLimitIntercept extends HandlerInterceptorAdapter {
@Autowired
private RedisTemplate
因为我的是Springboot2. 所以只需实现WebMvcConfigurer
如果是springboot1. 那就继承自 WebMvcConfigurerAdapter
然后重写addInterceptors() 添加自定义拦截器即可。@Slf4j
@Component
public class WebMvcConfig implements WebMvcConfigurer {
@Autowired
private RequestLimitIntercept requestLimitIntercept;
@Override
public void addInterceptors(InterceptorRegistry registry) {
log.info("添加拦截");
registry.addInterceptor(requestLimitIntercept);
}
}
控制层测试接口,
使用方式:
@RestController
@RequestMapping("/index")
@RequestLimit(maxCount = 5,second = 1)
public class IndexController {
/**
* @RequestLimit 修饰在方法上,优先使用其参数
* @return
*/
@GetMapping("/test1")
@RequestLimit
public Result test(){
//TODO ...
return Result.ok();
}
/**
* @RequestLimit 修饰在类上,用的是类的参数
* @return
*/
@GetMapping("/test2")
public Result test2(){
//TODO ...
return Result.ok();
}
}