拦截、限流,针对场景详细信息(一)

       以下是一个基于Java + Spring Boot + Redis 的完整限流实现案例,针对同一接口前缀(如  /one/ )的IP访问频率控制:

场景:用户不用登录即可访问接口,网站会有被攻击的风险

URL:one/two/three

         one/three/four

解决办法:

1. 核心代码实现

1.1 Redis 配置

@Configuration

public class RedisConfigNew {

    @Bean

    public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory factory) {

        RedisTemplate<String, Object> template = new RedisTemplate<>();

        template.setConnectionFactory(factory);

        template.setKeySerializer(new StringRedisSerializer());

        template.setValueSerializer(new GenericJackson2JsonRedisSerializer());

        return template;

    }

 

    @Bean

    public DefaultRedisScript<Long> rateLimitScript() {

        DefaultRedisScript<Long> script = new DefaultRedisScript<>();

        script.setScriptText(RATE_LIMIT_SCRIPT); // 加载Lua脚本

        script.setResultType(Long.class);

        return script;

    }

 

    private static final String RATE_LIMIT_SCRIPT = 

        "local key = KEYS[1]\n" +

        "local limit = tonumber(ARGV[1])\n" +

        "local expire = tonumber(ARGV[2])\n" +

        "local current = redis.call('INCR', key)\n" +

        "if current == 1 then\n" +

        " redis.call('EXPIRE', key, expire)\n" +

        "end\n" +

        "return current > limit and 1 or 0";

}

1.2 限流拦截器

@Component

public class RateLimitInterceptor implements HandlerInterceptor {

 

    @Autowired

    private RedisTemplate<String, Object> redisTemplate;

 

    @Autowired

    private DefaultRedisScript<Long> rateLimitScript;

 

    // 配置参数:每分钟最多60次请求,超时时间60秒

    private static final int DEFAULT_LIMIT = 60;

    private static final int DEFAULT_TIMEOUT = 60;

 

    @Override

    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws IOException {

        String ip = getClientIp(request);

        String uriPrefix = getUriPrefix(request); // 获取接口前缀,如 "bank"

 

        String key = "rate_limit:" + ip + ":" + uriPrefix;

 

        // 执行Lua脚本

        Long result = redisTemplate.execute(

            rateLimitScript, 

            Collections.singletonList(key), 

            DEFAULT_LIMIT, DEFAULT_TIMEOUT

        );

 

        if (result != null && result == 1) { // 超过限制

            response.setStatus(HttpStatus.TOO_MANY_REQUESTS.value());

            response.getWriter().write("Too many requests. Try again later.");

            return false;

        }

        return true;

    }

 

    private String getClientIp(HttpServletRequest request) {

        String ip = request.getHeader("X-Forwarded-For");

        if (ip == null || ip.isEmpty()) {

            ip = request.getRemoteAddr();

        } else {

            // 处理多个代理的情况,取第一个真实IP

            ip = ip.split(",")[0].trim();

        }

        return ip;

    }

 

    private String getUriPrefix(HttpServletRequest request) {

        String path = request.getRequestURI();

        return path.split("/")[1]; // 假设路径为 /one/xxx

    }

}

1.3 注册拦截器

@Configuration

public class WebMvcConfig implements WebMvcConfigurer {

 

    @Autowired

    private RateLimitInterceptor rateLimitInterceptor;

 

    @Override

    public void addInterceptors(InterceptorRegistry registry) {

        registry.addInterceptor(rateLimitInterceptor)

                .addPathPatterns("/one/**") // 拦截所有/one/开头的接口

                .excludePathPatterns("/one/login"); // 排除登录接口(如果需要)

    }

}

2. 关键点说明

2.1为什么用Lua脚本?

  • 原子性操作:INCR和EXPIRE必须在一个原子操作中完成,避免竞态条件。
  • 减少网络开销:Lua脚本在Redis服务器端执行,避免多次网络往返。

2.2如何应对突发流量?

  • 滑动窗口算法(可选升级):如果需要更精确的流量控制(例如每分钟允许100次,但允许前10秒集中访问),可以用 Redis Sorted Set 记录每次请求的时间戳,定期清理过期数据。

2.3如何扩展?

  • 动态调整限流阈值:将DEFAULT_LIMIT和DEFAULT_TIMEOUT参数存储在数据库或配置中心,支持动态更新。
  • 分布式限流:如果服务有多个实例,Redis 天然支持全局限流,无需额外配置。

3.注意事项

  • Redis连接池配置:确保连接池足够大,避免高并发下连接耗尽。
  • 限流粒度:当前案例是IP+接口前缀的组合限流,也可调整为用户ID+接口限流。
  • 异常处理:捕获Redis连接异常,避免服务雪崩(可用降级策略)。
  • 黑名单机制:对于多次触发限流的IP,可加入黑名单(用Redis的SETNX实现)。

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/pingmian/74066.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

计算机视觉算法实战——烟雾检测

✨个人主页欢迎您的访问 ✨期待您的三连 ✨ ✨个人主页欢迎您的访问 ✨期待您的三连 ✨ ✨个人主页欢迎您的访问 ✨期待您的三连✨ ​​​ ​​​​​​​​​ ​​ 1. 烟雾检测领域介绍 烟雾检测是计算机视觉在公共安全领域的重要应用&#xff0c;它通过分析视频或图像序…

MySQL-DCL函数

DCL DCL英文全称是Data Control Language(数据控制语言)&#xff0c;用来管理数据库用户、控制数据库的访问权限。 管理用户 1). 查询用户 use mysql; select * from user; select * from mysql.user; 查询的结果如下: 其中 Host代表当前用户访问的主机, 如果为localhost, 仅…

linux 服务器创建服务器启动后服务自启动

1、在/etc/systemd/system/下touch一个文件&#xff1a; touch /etc/systemd/system/your_application.service 2、在文件中写入&#xff1a; [Unit] Descriptionmodules-system Aftersyslog.target[Service] Typeforking Userroot Grouproot ExecStart/bin/bash /usr/loca…

端到端语音识别案例

《DeepSeek大模型高性能核心技术与多模态融合开发&#xff08;人工智能技术丛书&#xff09;》(王晓华)【摘要 书评 试读】- 京东图书 语音识别这一技术正如其名&#xff0c;是通过精密地解析说话人的语音来识别并准确转写出其所说的内容。它不仅仅是一个简单的转录过程&#…

QT——信号和槽

QT是图形化界面&#xff0c;自然是需要与用户进行交互的&#xff0c;但是该如何实现用户与界面或者程序的交互呢。答案是通过信号和槽。 一&#xff0c;什么是信号和槽&#xff1f; 在Linux操作系统里面&#xff0c;我们知道信号是由硬件或者软件产生&#xff0c;但是在QT里面…

Q:如何保证备份的有效性以及备份频率设置的优化方案?

1、如何保障备份数据的一致性 a) 快照 快照通过捕获数据在某一时刻的完整状态来保障备份一致性。在应用层&#xff0c;快照会暂停业务写入或生成事务一致性检查点&#xff08;如数据库的全局读视图&#xff09;&#xff0c;确保备份数据不包含未提交的事务&#xff1b;在存…

Linux实用操作及命令

一、各类小技巧&#xff08;快捷键&#xff09; 1、强制停止&#xff08;ctrlc&#xff09; Linux某些程序的运行&#xff0c;如果想要强制停止它&#xff0c;可以使用快捷键ctrl c 命令输入错误&#xff0c;也可以通过快捷键ctrl c&#xff0c;退出当前输入&#xff0c;重…

压测工具开发(一)——使用Qt Designer构建简单界面

你好&#xff0c;我是安然无虞。 文章目录 项目功能概述构建菜单栏、工具栏1. 菜单栏注意事项2. 工具栏注意事项3. 日志停靠窗口 项目功能概述 开发一款 Qt版本的压测工具, 可以用来做 基于HTTP API接口的 性能测试. 要求做一个 MDI 多功能子窗口的 图形界面程序, 方便公司内…

Ubuntu 22 Linux上部署DeepSeek R1保姆式操作详解(ollama方式)

操作系统&#xff1a;Ubuntu Linux 22.04 一、安装模型运行环境 打开链接https://ollama.com/download/linux 1.安装ollama &#xff08;1&#xff09;一条指令即可实现的简易版安装方法&#xff08;也可称为在线安装&#xff09; curl -fsSL https://ollama.com/install.s…

MySQL 和 Redis 数据一致性解决方案

MySQL 和 Redis 数据一致性解决方案 MySQL 和 Redis 作为两种不同类型的数据库(关系型 vs 内存型)&#xff0c;在配合使用时需要特别注意数据一致性问题。以下是几种常见的解决方案&#xff1a; 1. 缓存更新策略 1.1 Cache Aside Pattern (旁路缓存模式) 读操作&#xff1a…

Java高频面试之集合-20

hello啊&#xff0c;各位观众姥爷们&#xff01;&#xff01;&#xff01;本baby今天来报道了&#xff01;哈哈哈哈哈嗝&#x1f436; 面试官&#xff1a;讲讲 HashSet 的底层实现&#xff1f; HashSet 是 Java 集合框架中用于存储唯一元素的高效数据结构&#xff0c;其底层实…

【MySQL】从零开始:掌握MySQL数据库的核心概念(四)

人们之所以不愿改变&#xff0c;是因为害怕未知。但历史唯一不变的事实&#xff0c;就是一切都会改变。 前言 这是我自己学习mysql数据库的第四篇博客总结。后期我会继续把mysql数据库学习笔记开源至博客上。 上一期笔记是关于mysql数据库的表格约束&#xff0c;没看的同学可以…

Manus:通用智能体的架构革命与产业破局

&#x1f90d; 前端开发工程师、技术日更博主、已过CET6 &#x1f368; 阿珊和她的猫_CSDN博客专家、23年度博客之星前端领域TOP1 &#x1f560; 牛客高级专题作者、打造专栏《前端面试必备》 、《2024面试高频手撕题》、《前端求职突破计划》 &#x1f35a; 蓝桥云课签约作者、…

HTTP协议手写服务器

目录 一、请求的是Web根目录 二、GET方法通过URL传参 三、根据资源类型对应出Content-Type值 四、Http代码 项目完整源代码&#xff1a;Http 周不才/cpp_linux study - 码云 - 开源中国 一、请求的是Web根目录 如果URL中请求的资源是Web根目录&#xff0c;则自动跳转到主…

小蓝和钥匙

错位排序组合数 从28个人里面选14个人分到原来房间的钥匙 C 28 14 另外14个人错位排序 模板 请在此处填写你的解题思路 D14 都是模板记住就好了 无需理解 做题可以看出来是错位排序 或者组合数 然后会写代码就行了 import java.util.Scanner;/*** author zb* date2025/3…

使用飞书API自动化更新共享表格数据

飞书API开发之自动更新共享表格 天马行空需求需求拆解1、网站数据爬取2、飞书API调用2.1 开发流程2.2 创建应用2.3 配置应用2.4 发布应用2.5 修改表格权限2.6 获取tenant_access_token2.7 调用API插入数据 总结 天马行空 之前一直都是更新的爬虫逆向内容&#xff0c;工作中基本…

Python-Django入手

18.1 建立项目 18.1.1 制定规范 - 定义项目目标&#xff1a;明确应用的核心功能 - 创建项目文档&#xff1a;用README.md记录技术栈和开发流程 - 规划目录结构&#xff1a;建议遵循Django官方推荐的项目布局 18.1.2 建立虚拟环境 在命令行执行&#xff1a; python -m ven…

LangChain4j 入门(二)

LangChain 整合 SpringBoot 下述代码均使用 阿里云百炼平台 提供的模型。 创建项目&#xff0c;引入依赖 通过 IDEA 创建 SpringBoot 项目&#xff0c;并引入 Spring Web 依赖&#xff0c;SpringBoot 推荐使用 3.x 版本。 引入 LangChain4j 和 WebFlux 依赖 <!--阿里云 D…

3.30学习总结 Java包装类+高精度算法+查找算法

包装类&#xff1a; 基本数据类型对应的引用数据类型。 基本数据类型&#xff1a;在内存中记录的是真实的值。 八种包装类的父类都是Object类。 对象之间不能直接进行计算。 JDK5之后可以把int和integer看成一个东西&#xff0c;因为会进行内部优化。自动装箱和自动拆箱。 …

centos 7 LVM管理命令

物理卷&#xff08;PV&#xff09;管理命令 pvcreate&#xff1a;用于将物理磁盘分区或整个磁盘创建为物理卷。 示例&#xff1a;sudo pvcreate /dev/sdb1 解释&#xff1a;将 /dev/sdb1 分区创建为物理卷。 pvdisplay&#xff1a;显示物理卷的详细信息&#xff0c;如大小、所属…