通过Interceptor以及Redis实现接口访问防刷
方式一
以下是通过Interceptor以及Redis实现接口访问防刷的Java代码示例:
首先,创建一个自定义拦截器类,实现HandlerInterceptor接口,并在preHandle方法中添加接口防刷逻辑。例如:
@Component
public class RateLimiterInterceptor implements HandlerInterceptor {
private static final String RATE_LIMITER_KEY_PREFIX = "rate_limiter:";
private static final int MAX_REQUESTS_PER_SECOND = 10;
private final RedisTemplate<String, String> redisTemplate;
@Autowired
public RateLimiterInterceptor(RedisTemplate<String, String> redisTemplate) {
this.redisTemplate = redisTemplate;
}
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
String ip = request.getRemoteAddr();
String key = RATE_LIMITER_KEY_PREFIX + ip;
Long count = redisTemplate.opsForValue().increment(key, 1);
if (count == 1) {
// Set a TTL to the key so it gets deleted after one second.
redisTemplate.expire(key, 1, TimeUnit.SECONDS);
}
if (count > MAX_REQUESTS_PER_SECOND) {
response.setStatus(HttpStatus.TOO_MANY_REQUESTS.value());
return false;
}
return true;
}
}
上述代码中,我们使用了Redis作为存储桶,每个IP地址对应一个key,每一次请求就将key中的计数器加一,并设置一个过期时间为1秒钟。如果计数器超过最大请求数,则返回HTTP 429 Too Many Requests响应。
接下来,在Spring Boot应用程序中配置拦截器,例如:
@Configuration
public class WebConfig implements WebMvcConfigurer {
private final RateLimiterInterceptor rateLimiterInterceptor;
@Autowired
public WebConfig(RateLimiterInterceptor rateLimiterInterceptor) {
this.rateLimiterInterceptor = rateLimiterInterceptor;
}
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(rateLimiterInterceptor);
}
}
这样,我们就可以实现接口访问防刷功能了。每个IP地址在1秒钟内最多只能发送10个请求。如果超过限制,则返回HTTP 429响应。
方式二
以下是通过Interceptor以及Redis 自定义注解 + 反射 实现接口访问防刷的Java代码示例:
首先,创建一个自定义注解@RateLimit,并在注解中添加限制参数。例如:
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface RateLimit {
int limit() default 10;
int timeout() default 1;
}
然后,在服务启动时,使用反射扫描所有带有@RateLimit注解的方法,并生成对应的拦截器和key。例如:
@Component
public class RateLimiterBeanPostProcessor implements BeanPostProcessor, ApplicationContextAware {
private final Map<Method, String> rateLimiterMap = new HashMap<>();
private ApplicationContext applicationContext;
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
Class<?> clazz = bean.getClass();
Method[] methods = clazz.getDeclaredMethods();
for (Method method : methods) {
RateLimit annotation = AnnotationUtils.findAnnotation(method, RateLimit.class);
if (annotation != null) {
int limit = annotation.limit();
int timeout = annotation.timeout();
String key = "rate_limiter:" + clazz.getName() + ":" + method.getName() + ":" +
Arrays.toString(method.getParameterTypes());
RedisTemplate<String, String> redisTemplate = applicationContext.getBean(RedisTemplate.class);
RateLimiterInterceptor rateLimiterInterceptor = new RateLimiterInterceptor(redisTemplate, key, limit, timeout);
this.rateLimiterMap.put(method, key);
WebMvcConfigurer appConfig = (WebMvcConfigurer) applicationContext.getBean(WebMvcConfigurer.class);
appConfig.addInterceptors(rateLimiterInterceptor);
}
}
return bean;
}
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
this.applicationContext = applicationContext;
}
}
上述代码中,我们通过注解扫描所有带有@RateLimit注解的方法,并在应用程序启动时生成对应的拦截器和key。这里使用了RedisTemplate将key与计数器存储到Redis中。
接下来,创建一个自定义拦截器类RateLimiterInterceptor,并在preHandle方法中添加接口防刷逻辑。其中,根据之前生成的key从Redis中获取对应的计数器并进行限制。例如:
public class RateLimiterInterceptor implements HandlerInterceptor {
private final RedisTemplate<String, String> redisTemplate;
private final String key;
private final int limit;
private final int timeout;
public RateLimiterInterceptor(RedisTemplate<String, String> redisTemplate, String key, int limit, int timeout) {
this.redisTemplate = redisTemplate;
this.key = key;
this.limit = limit;
this.timeout = timeout;
}
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
String ip = request.getRemoteAddr();
String realKey = key + ":" + ip;
Long count = redisTemplate.opsForValue().increment(realKey, 1);
redisTemplate.expire(realKey, timeout, TimeUnit.SECONDS);
if (count > limit) {
response.setStatus(HttpStatus.TOO_MANY_REQUESTS.value());
return false;
}
return true;
}
}
最后,在需要限制访问的接口方法上添加@RateLimit注解,例如:
@RestController
public class HelloController {
@RateLimit(limit = 5, timeout = 1)
@GetMapping("/hello")
public String hello() {
return "Hello World";
}
}
这样,我们就可以实现接口访问防刷功能了。每个IP地址在1秒钟内最多只能发送5个请求。如果超过限制,则返回HTTP 429响应。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本
· Manus爆火,是硬核还是营销?
· 终于写完轮子一部分:tcp代理 了,记录一下
· 别再用vector<bool>了!Google高级工程师:这可能是STL最大的设计失误
· 单元测试从入门到精通