使用Redis和Nginx分别实现限制接口请求频率
前言
为啥需要限制接口请求频率?这个是因为防止接口一直被刷,比如发送手机验证码的接口,一直被刷的话,费钱费资源的,至少做点基本的防护工作。以下分别使用Redis和Nginx实现限制接口请求频率方案。
一、基于Redis实现接口限流
1.ZADD 命令
(1)用法:ZADD key score_1 value_1 score_2 value_2 ...
(2)作用:将一个或多个成员元素及其分数值加入到有序集当中。某个成员已经是有序集的成员,那么更新这个成员的分数值,并通过重新插入这个成员元素,来保证该成员在正确的位置上。分数值可以是整数值或双精度浮点数。
(3)返回值:被成功添加的新成员的数量,不包括那些被更新的、已经存在的成员。
(4)示例
redis > ZADD runoobkey 1 redis
(integer) 1
redis > ZADD runoobkey 2 mongodb
(integer) 1
redis > ZADD runoobkey 3 mysql
(integer) 1
redis > ZADD runoobkey 3 mysql
(integer) 0
redis > ZADD runoobkey 4 mysql
(integer) 0
redis > ZRANGE runoobkey 0 10 WITHSCORES1) "redis"
2) "1"
3) "mongodb"
4) "2"
5) "mysql"
6) "4"
2.ZREM 命令
(1)用法:ZREM key value_1 value_2 ...
(2)作用:移除有序集中的一个或多个成员,不存在的成员将被忽略。
(3)返回值:被成功添加的新成员的数量,不包括那些被更新的、已经存在的成员。
(4)示例
redis > ZRANGE runoobkey 0 10 WITHSCORES1) "redis"
2) "1"
3) "mongodb"
4) "2"
5) "mysql"
6) "4"redis > ZREM mongodb
(integer) 1redis > ZRANGE runoobkey 0 10 WITHSCORES
1) "redis"
2) "1"
3) "mysql"
4) "4"
3.ZCARD 命令
(1)用法:ZCARD key
(2)作用:获取有序集合中成员的数量。
(3)返回值:当key存在且是有序集类型时,返回有序集的基数。 当key不存在时,返回0 。
(4)示例
redis > ZADD myzset 1 "one"
(integer) 1
redis > ZADD myzset 2 "two"
(integer) 1
redis > ZCARD myzset
(integer) 2
4.ZREMRANGEBYSCORE 命令
(1)用法:ZREMRANGEBYSCORE key min max
(2)作用:移除有序集中,指定分数区间内的所有成员。
(3)返回值:被移除成员的数量。
(4)示例
redis > ZRANGE salary 0 -1 WITHSCORES
1) "tom"
2) "2000"
3) "peter"
4) "3500"
5) "jack"
6) "5000"redis > ZREMRANGEBYSCORE salary 1500 3500
(integer) 2redis> ZRANGE salary 0 -1 WITHSCORES
1) "jack"
2) "5000"
5.具体实现
(1)新建一个过滤器,如【/src/main/java/org/example/interceptor/RateLimiterInterceptor.java】
package org.example.interceptor;import cn.hutool.json.JSONObject;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.http.HttpStatus;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.HandlerInterceptor;import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.HashMap;
import java.util.concurrent.TimeUnit;/*** 限流拦截器*/
@Component
public class RateLimiterInterceptor implements HandlerInterceptor {private static final String RATE_LIMITER_PREFIX = "Rate-Limiter:";private static final int LIMIT = 10; // 限流阈值private static final int TIME_WINDOW = 60; // 时间窗口,单位为秒@Autowiredprivate StringRedisTemplate stringRedisTemplate;@Overridepublic boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {response.setCharacterEncoding("utf-8");response.setContentType("application/json");String key = RATE_LIMITER_PREFIX + request.getRequestURI() + ":" + request.getRemoteAddr(); // Rate-Limiter:/api/sendCode:127.0.0.1long currentTime = System.currentTimeMillis(); // 1703036748554long beforeTime = currentTime - TIME_WINDOW * 1000; // 1703036748554 - 60000 = 1703036688554// Long removeNum = stringRedisTemplate.opsForZSet().removeRangeByScore(K key, double min, double max); // 删除有序集合中分数在指定范围内的元素,返回删除元素的数量stringRedisTemplate.opsForZSet().removeRangeByScore(key, 0, beforeTime); // 删除有序集合中60秒之前存进去的所有数据,如:// Long memberNum = stringRedisTemplate.opsForZSet().size(K key); // 获取有序集合中元素的数量long count = stringRedisTemplate.opsForZSet().size(key); // 3if (count >= LIMIT) {HashMap<String, Object> responseObj = new HashMap<>();responseObj.put("code", HttpStatus.TOO_MANY_REQUESTS.value());responseObj.put("success", false);responseObj.put("msg", HttpStatus.TOO_MANY_REQUESTS.getReasonPhrase());JSONObject json = new JSONObject(responseObj);response.getWriter().println(json);return false;} else {// Boolean addFlag = stringRedisTemplate.opsForZSet().add(K var1, V var2, double var3); // 向有序集合中添加一个或多个元素,并指定其分数stringRedisTemplate.opsForZSet().add(key, String.valueOf(currentTime), currentTime);// Boolean expireFlag = stringRedisTemplate.expire(K key, long timeout, TimeUnit unit); // 对指定key的数据设置过期时间stringRedisTemplate.expire(key, TIME_WINDOW, TimeUnit.SECONDS);return true;}}
}
(2)在SpringMVC配置类中注入此过滤器,如【/src/main/java/org/example/config/ResourceConfig.java】
package org.example.config;import org.example.interceptor.RateLimiterInterceptor;
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.WebMvcConfigurationSupport;@Configuration
public class ResourceConfig extends WebMvcConfigurationSupport {@Autowiredprivate RateLimiterInterceptor rateLimiterInterceptor;@Overridepublic void addInterceptors(InterceptorRegistry registry) {registry.addInterceptor(rateLimiterInterceptor).addPathPatterns("/abcd/api/sendCode");}
}
6.运行效果
// ~
二、基于Nginx实现接口限流
1.在nginx.conf文件中新增限流配置
user nginx;
worker_processes 1;error_log /var/log/nginx/error.log warn;
pid /var/run/nginx.pid;events {worker_connections 1024;
}http {include /etc/nginx/mime.types;default_type application/octet-stream;log_format main '$remote_addr - $remote_user [$time_local] "$request" ''$status $body_bytes_sent "$http_referer" ''"$http_user_agent" "$http_x_forwarded_for"';access_log /var/log/nginx/access.log main;sendfile on;#tcp_nopush on;keepalive_timeout 65;#gzip on;include /etc/nginx/conf.d/*.conf;# 负载均衡upstream springboot {server xxx.xxx.xxx.xxx:8080;}# limit_req_zone $binary_remote_addr zone=limit_zone:10m rate=10r/s; # 定义了一个名为limit_zone的限流区域,使用IP地址进行限流,该区域的大小为10MB,限流速率为10个请求每秒。limit_req_zone $binary_remote_addr zone=limit_zone:10m rate=10r/m; # 定义了一个名为limit_zone的限流区域,使用IP地址进行限流,该区域的大小为10MB,限流速率为10个请求每分钟。# 80端口的服务server { listen 80;server_name xxx.xxx.xxx.xxx;location / {alias html;index index.html index.htm;try_files $uri $uri/ /love/index.html;proxy_pass http://localhost;}location ^~ /love/ {root html/love;index index.html index.htm;proxy_pass http://localhost;}location ^~ /abcd/api/sendCode {# 在/xxx/api/sendCode接口的location中使用limit_req指令进行限流,限流区域为limit_zone,同时设置了一个瞬时突发流量为20个请求的阈值。# 这样,当同一个IP地址在一秒钟内发送超过10个请求到此接口时,Nginx会返回503错误码,表示请求被限流了。# limit_req zone=limit_zone burst=20;# 在/xxx/api/sendCode接口的location中使用limit_req指令进行限流,限流区域为limit_zone,同时设置了一个瞬时突发流量为5个请求的阈值。# 这样,当同一个IP地址在一秒钟内发送超过10个请求到此接口时,如果在一分钟内有超过10个请求,则允许其中的5个请求通过,nodelay表示不延迟响应,即立即返回503错误码。limit_req zone=limit_zone burst=5 nodelay;proxy_pass http://springboot;}}
}
2.运行效果
// ~
相关文章:
使用Redis和Nginx分别实现限制接口请求频率
前言 为啥需要限制接口请求频率?这个是因为防止接口一直被刷,比如发送手机验证码的接口,一直被刷的话,费钱费资源的,至少做点基本的防护工作。以下分别使用Redis和Nginx实现限制接口请求频率方案。 一、基于Redis实现…...

ansible模块 (7-13)
模块 7、hostname模块: 远程主机名管理模块 ansible 192.168.10.202 -m hostname -a nameliu 8、copy模块: 用于复制指定的主机文件到远程主机的模块 常用参数: dest: 指出要复制的文件在哪,必须使用绝对路径。如果源目标是…...

MySQL概括与SQL分类
文章目录 一、计算机语言二、SQL语言三、数据库系统四、MySQL简介 一、计算机语言 二、SQL语言 三、数据库系统 四、MySQL简介...
微信小程序:wx:for 获取view点击的元素currentTarget.dataset为空
遍历数组渲染一组view通过bindtap事件获取点击的元素 解决办法: 在遍历时,设置data-item即可。 示例: <view wx:for"{{types}}" data-item"{{item}}"wx:key"key" bindtap"syntheActiveItem"c…...

Word的兼容性问题很常见,禁用兼容模式虽步不是最有效的,但可以解决兼容性问题
当你在较新版本的Word应用程序中打开用较旧版本的Word创建的文档时,会出现兼容性问题。错误通常发生在文件名附近(兼容模式)。兼容性模式问题(暂时)禁用Word功能,从而限制使用较新版本Word的用户编辑文档。…...

环境搭建及源码运行_java环境搭建_idea版本下载及安装
1、介绍 Idea是一款被广泛使用的Java集成开发环境,它提供了丰富的功能和工具来帮助开发人员更高效地编写和调试代码。作为一款开源软件,Idea不仅提供了基本的代码编辑、自动完成和调试功能,还支持大量的插件和扩展,可为开发人员提…...

jvm相关命令操作
查看jvm使用情况 jmap -heap PID 查看线程使用情况 jstack pid 查看当前线程数 jstack 21294 |grep -E (#[0-9]) -o -c 查看系统线程数 top -H top -Hp pid #查看具体的进程中的线程信息 使用 jps 命令查看配置了JVM的服务 查看某个进程JVM的GC使用情况 jstat -gc 进程…...

芋道前端框架上线之后发现element-ui的icon图标全部乱码
前言 最近发现线上有人反映图标全部是乱码,登录上去看确实乱码,刷新就好最后一顿搜,发现是sass版本不兼容导致的图标乱码问题 解决办法 1.先把sass升级到1.39.0 2.来到vue.config.js文件配置代码-如果是芋道前端框架不用配置自带 css: {lo…...

每个伦敦金投资者都应该练习的日线图交易
在伦敦金市场中,每个投资者都应该试着去做日线图的交易。有的人一听到日线图马上摇头,原因是日线图的价格跨度大,导致止损距离也变大,这样对投资者来说无疑是增加了风险。如果资金量大的投资者还好说,可以降低仓位&…...

高通平台开发系列讲解(USB篇)adb应用adbd分析
沉淀、分享、成长,让自己和他人都能有所收获!😄 在apps_proc/system/core/adb/adb_main.cpp文件中main()函数会调用adb_main()函数,然后调用uab_init函数 在uab_init()函数中,会创建一个线程,在线程中会调用init_functionfs()函数,利用ep0控制节点,创建ep1、ep2输…...

【上海大学数字逻辑实验报告】七、中规模元件及综合设计
一、实验目的 掌握中规模时序元件的测试。学会在Quartus II上设计序列发生器。 二、实验原理 74LS161是四位可预置数二进制加计数器,采用16引脚双列直插式封装的中规模集成电路,其外形如下图所示: 其各引脚功能为: 异步复位输…...

JVM内存结构Java内存模型Java对象模型
导图: https://naotu.baidu.com/file/60a0bdcaca7c6b92fcc5f796fe6f6bc9 1.JVM内存结构&&Java内存模型&&Java对象模型 1.1.JVM内存结构 1.2.Java对象模型 Java对象模型表示的是这个对象本身的存储模型,JVM会给这个类创建一个instanceKlass保存在方…...

Istio 社区周报(第一期):2023.12.11 - 12.17
欢迎来到 Istio 社区周报 Istio 社区朋友们,你们好! 我很高兴呈现第一期 Istio 社区周报。作为 Istio 社区的一员,每周我将为您带来 Istio 的最新发展、有见地的社区讨论、专业提示和重要安全新闻内容。 祝你阅读愉快,并在下一期中…...
质量图导向法解包裹之---计算边缘可靠性
在这之前需要我们知道像素点的可靠性 % 这反映了相位变化的平滑程度。以下是一个可能的实现,它使用了二阶差分来计算可靠性: function rel calculateReliability(wrappedPhase)% 应用高斯滤波减少噪声filteredImg imgaussfilt(wrappedPhase, 2); % 2 …...

C# WPF上位机开发(进度条操作)
【 声明:版权所有,欢迎转载,请勿用于商业用途。 联系信箱:feixiaoxing 163.com】 软件上面如果一个操作比较缓慢,或者说需要很长的时间,那么这个时候最好添加一个进度条,提示一下当前任务的进展…...

vulnhub-Tre(cms渗透)
靶机和kali都使用net网络,方便探测主机获取ip1.靶机探测 使用fping扫描net网段 靶机ip:192.168.66.130 2.端口扫描 扫描发现该靶机三个端口,ssh,还有两个web,使用的中间件也是不一样的,一个是apache&…...

Re解析(正则表达式解析)
正则表达式基础 元字符 B站教学视频: 正则表达式元字符基本使用 量词 贪婪匹配和惰性匹配 惰性匹配如下两张图,而 .* 就表示贪婪匹配,即尽可能多的匹配到符合的字符串,如果使用贪婪匹配,那么结果就是图中的情况三 p…...

HTML输出特殊字符详细方法
以下是部分特殊字符代码表,它们的完整应用代码格式为:&#;用下面的四位数字替换,将得到对应的符号。(注意:应用这些代码,编辑器应该切换到HTML模式) ☏260f ☎260e ☺263a ☻263b ☼263c ☽…...
《漫画算法》笔记——计算两个大数的和
例题: 输入:“123”,“234” 输出:“357” 思路: 使用数组,分别计算每一位上的加和,注意记录进位信息。 然后,将数组恢复成字符串,输出。 值得注意的是,加和…...
Python3.13版本改进规划
大家好,最近faster-cpython 项目的文档介绍了关于 Python 3.13 的规划,以及在 3.13 版本中将要实现的一些优化和改进。faster-python 是 Python 的创始人 Guido van Rossum 和他的团队提出的计划 ,目标是在四年内将 CPython 的性能提升五倍。…...
Java如何权衡是使用无序的数组还是有序的数组
在 Java 中,选择有序数组还是无序数组取决于具体场景的性能需求与操作特点。以下是关键权衡因素及决策指南: ⚖️ 核心权衡维度 维度有序数组无序数组查询性能二分查找 O(log n) ✅线性扫描 O(n) ❌插入/删除需移位维护顺序 O(n) ❌直接操作尾部 O(1) ✅内存开销与无序数组相…...

Nuxt.js 中的路由配置详解
Nuxt.js 通过其内置的路由系统简化了应用的路由配置,使得开发者可以轻松地管理页面导航和 URL 结构。路由配置主要涉及页面组件的组织、动态路由的设置以及路由元信息的配置。 自动路由生成 Nuxt.js 会根据 pages 目录下的文件结构自动生成路由配置。每个文件都会对…...
镜像里切换为普通用户
如果你登录远程虚拟机默认就是 root 用户,但你不希望用 root 权限运行 ns-3(这是对的,ns3 工具会拒绝 root),你可以按以下方法创建一个 非 root 用户账号 并切换到它运行 ns-3。 一次性解决方案:创建非 roo…...
Spring Boot面试题精选汇总
🤟致敬读者 🟩感谢阅读🟦笑口常开🟪生日快乐⬛早点睡觉 📘博主相关 🟧博主信息🟨博客首页🟫专栏推荐🟥活动信息 文章目录 Spring Boot面试题精选汇总⚙️ **一、核心概…...
解决本地部署 SmolVLM2 大语言模型运行 flash-attn 报错
出现的问题 安装 flash-attn 会一直卡在 build 那一步或者运行报错 解决办法 是因为你安装的 flash-attn 版本没有对应上,所以报错,到 https://github.com/Dao-AILab/flash-attention/releases 下载对应版本,cu、torch、cp 的版本一定要对…...

【7色560页】职场可视化逻辑图高级数据分析PPT模版
7种色调职场工作汇报PPT,橙蓝、黑红、红蓝、蓝橙灰、浅蓝、浅绿、深蓝七种色调模版 【7色560页】职场可视化逻辑图高级数据分析PPT模版:职场可视化逻辑图分析PPT模版https://pan.quark.cn/s/78aeabbd92d1...

Aspose.PDF 限制绕过方案:Java 字节码技术实战分享(仅供学习)
Aspose.PDF 限制绕过方案:Java 字节码技术实战分享(仅供学习) 一、Aspose.PDF 简介二、说明(⚠️仅供学习与研究使用)三、技术流程总览四、准备工作1. 下载 Jar 包2. Maven 项目依赖配置 五、字节码修改实现代码&#…...

【电力电子】基于STM32F103C8T6单片机双极性SPWM逆变(硬件篇)
本项目是基于 STM32F103C8T6 微控制器的 SPWM(正弦脉宽调制)电源模块,能够生成可调频率和幅值的正弦波交流电源输出。该项目适用于逆变器、UPS电源、变频器等应用场景。 供电电源 输入电压采集 上图为本设计的电源电路,图中 D1 为二极管, 其目的是防止正负极电源反接, …...
Java数值运算常见陷阱与规避方法
整数除法中的舍入问题 问题现象 当开发者预期进行浮点除法却误用整数除法时,会出现小数部分被截断的情况。典型错误模式如下: void process(int value) {double half = value / 2; // 整数除法导致截断// 使用half变量 }此时...
LRU 缓存机制详解与实现(Java版) + 力扣解决
📌 LRU 缓存机制详解与实现(Java版) 一、📖 问题背景 在日常开发中,我们经常会使用 缓存(Cache) 来提升性能。但由于内存有限,缓存不可能无限增长,于是需要策略决定&am…...