根据ip限制接口访问次数

2024-05-15 02:28
文章标签 ip 接口 访问 次数 限制

本文主要是介绍根据ip限制接口访问次数,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

前言

我们利用redis去实现这个功能,redis的天然高并发和内存单线程速度拉满,非常适合做这个场景。为了可用性,我们把它封装成注解形式,哪个接口想被根据ip限制接口访问次数,直接标注上注解即可。

一、添加配置

在yaml文件中添加如下配置:

spring.redis.host: 172.xx.xx.xx
spring.redis.port: 6379
spring.redis.database: 1
spring.redis.password: tenxcloud

二、封装注解

封装一个注解使用,并且给一个默认值,防止空指针异常。

package com.xxx.ai.intelligentqa.annotate;import java.lang.annotation.*;/*** 接口访问频率注解,默认一分钟只能访问20次*/@Documented
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface RequestLimit {// 限制时间 单位:秒(默认值:一分钟)long period() default 60;// 允许请求的次数(默认值:20次)long count() default 20;
}

三、主体逻辑切面实现

我们利用AOP的切面,来配合注解实现限流逻辑:

package com.xxx.ai.intelligentqa.aop;import com.xxx.ai.intelligentqa.annotate.RequestLimit;
import com.xxx.ai.intelligentqa.tools.RequestUtil;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.BoundSetOperations;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.core.ZSetOperations;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import org.springframework.web.servlet.mvc.method.annotation.SseEmitter;import javax.servlet.http.HttpServletRequest;
import java.util.concurrent.TimeUnit;@Aspect
@Component
public class RequestLimitAspect {@AutowiredStringRedisTemplate redisTemplate;private static final Logger logger = LoggerFactory.getLogger(RequestLimitAspect.class);private static final String blackListKey = "ai:black_list";// 切点@Pointcut("@annotation(requestLimit)")public void controllerAspect(RequestLimit requestLimit) {}@Around("controllerAspect(requestLimit)")public Object doAround(ProceedingJoinPoint joinPoint, RequestLimit requestLimit) throws Throwable {SseEmitter emitter = new SseEmitter(0L);//获取当前请求request对象ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();if (attributes == null) {throw new IllegalStateException("在上下文中没有请求的属性,可能是非web程序访问。");}HttpServletRequest request = attributes.getRequest();long period = requestLimit.period();long limitCount = requestLimit.count();String ip = RequestUtil.getIpAdrress(request); //解析出来真是请求的ip,防止多重代理ip攻击String uri = request.getRequestURI();String key = "ai:req_limit_".concat(uri).concat(":").concat(ip);// 检查用户IP是否在黑名单中BoundSetOperations<String, String> blackListOperations = redisTemplate.boundSetOps(blackListKey);if (blackListOperations.isMember(ip)) {logger.error("接口拦截:真实IP为{},已经在黑名单中", ip);//这里被我aop环绕的接口返回值是sse类型,所以此处我也需要使用sse形式返回。根据你接口返回值来SseEmitter emitter = new SseEmitter(0L);emitter.send(SseEmitter.event().name(AppConsts.EVENT_ERROR).data("您的请求过于频繁,请于5分钟后再次访问"));emitter.complete();return emitter;}ZSetOperations zSetOperations = redisTemplate.opsForZSet();// 添加当前时间戳long currentMs = System.currentTimeMillis();//zSetOperations.add(key, currentMs, currentMs);zSetOperations.add(key, String.valueOf(currentMs), currentMs);// 设置用户的过期时间redisTemplate.expire(key, period, TimeUnit.SECONDS);// 删除当前窗口之外的值(如果时间窗口是60秒,那么在60秒内的同一IP请求会被计数,超过60秒的请求就不应该再被计数了,因为它们已经滑出时间窗口了)Long aLong = zSetOperations.removeRangeByScore(key, 0, currentMs - period * 1000);// 检查所有可用计数Long count = zSetOperations.zCard(key);if (count > limitCount) {logger.error("接口拦截:{} 请求超过限制频率【{}次/{}s】,真实IP为{}", uri, limitCount, period, ip);// 将用户IP添加到黑名单并设置过期时间为5分钟(300秒)blackListOperations.add(ip);redisTemplate.expire(blackListKey, 300, TimeUnit.SECONDS);SseEmitter emitter = new SseEmitter(0L);emitter.send(SseEmitter.event().name(AppConsts.EVENT_ERROR).data("系统繁忙,请稍后重试"));emitter.complete();return emitter;}// 如果条件不成立,将继续执行 controller 层的方法return  joinPoint.proceed();}
}

四、把注解加在想要限流的接口上

@RequestLimit(count = 30)public Result knowledgeConverseEvents(QAAppDto dto, FacadeBase FacadeBase) {return appIntelligentAS.knowledgeConverseStream(dto);}

这篇关于根据ip限制接口访问次数的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/990547

相关文章

MySQL中的InnoDB单表访问过程

《MySQL中的InnoDB单表访问过程》:本文主要介绍MySQL中的InnoDB单表访问过程,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录1、背景2、环境3、访问类型【1】const【2】ref【3】ref_or_null【4】range【5】index【6】

全面解析MySQL索引长度限制问题与解决方案

《全面解析MySQL索引长度限制问题与解决方案》MySQL对索引长度设限是为了保持高效的数据检索性能,这个限制不是MySQL的缺陷,而是数据库设计中的权衡结果,下面我们就来看看如何解决这一问题吧... 目录引言:为什么会有索引键长度问题?一、问题根源深度解析mysql索引长度限制原理实际场景示例二、五大解决

前端如何通过nginx访问本地端口

《前端如何通过nginx访问本地端口》:本文主要介绍前端如何通过nginx访问本地端口的问题,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录一、nginx安装1、下载(1)下载地址(2)系统选择(3)版本选择2、安装部署(1)解压(2)配置文件修改(3)启动(4)

SpringBoot+Redis防止接口重复提交问题

《SpringBoot+Redis防止接口重复提交问题》:本文主要介绍SpringBoot+Redis防止接口重复提交问题,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不... 目录前言实现思路代码示例测试总结前言在项目的使用使用过程中,经常会出现某些操作在短时间内频繁提交。例

Spring Boot 实现 IP 限流的原理、实践与利弊解析

《SpringBoot实现IP限流的原理、实践与利弊解析》在SpringBoot中实现IP限流是一种简单而有效的方式来保障系统的稳定性和可用性,本文给大家介绍SpringBoot实现IP限... 目录一、引言二、IP 限流原理2.1 令牌桶算法2.2 漏桶算法三、使用场景3.1 防止恶意攻击3.2 控制资源

springboot下载接口限速功能实现

《springboot下载接口限速功能实现》通过Redis统计并发数动态调整每个用户带宽,核心逻辑为每秒读取并发送限定数据量,防止单用户占用过多资源,确保整体下载均衡且高效,本文给大家介绍spring... 目录 一、整体目标 二、涉及的主要类/方法✅ 三、核心流程图解(简化) 四、关键代码详解1️⃣ 设置

spring中的ImportSelector接口示例详解

《spring中的ImportSelector接口示例详解》Spring的ImportSelector接口用于动态选择配置类,实现条件化和模块化配置,关键方法selectImports根据注解信息返回... 目录一、核心作用二、关键方法三、扩展功能四、使用示例五、工作原理六、应用场景七、自定义实现Impor

SpringBoot服务获取Pod当前IP的两种方案

《SpringBoot服务获取Pod当前IP的两种方案》在Kubernetes集群中,SpringBoot服务获取Pod当前IP的方案主要有两种,通过环境变量注入或通过Java代码动态获取网络接口IP... 目录方案一:通过 Kubernetes Downward API 注入环境变量原理步骤方案二:通过

MybatisPlus service接口功能介绍

《MybatisPlusservice接口功能介绍》:本文主要介绍MybatisPlusservice接口功能介绍,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友... 目录Service接口基本用法进阶用法总结:Lambda方法Service接口基本用法MyBATisP

如何搭建并配置HTTPD文件服务及访问权限控制

《如何搭建并配置HTTPD文件服务及访问权限控制》:本文主要介绍如何搭建并配置HTTPD文件服务及访问权限控制的问题,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录一、安装HTTPD服务二、HTTPD服务目录结构三、配置修改四、服务启动五、基于用户访问权限控制六、