使用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 的性能提升五倍。…...

Linux应用开发之网络套接字编程(实例篇)
服务端与客户端单连接 服务端代码 #include <sys/socket.h> #include <sys/types.h> #include <netinet/in.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <arpa/inet.h> #include <pthread.h> …...

CTF show Web 红包题第六弹
提示 1.不是SQL注入 2.需要找关键源码 思路 进入页面发现是一个登录框,很难让人不联想到SQL注入,但提示都说了不是SQL注入,所以就不往这方面想了 先查看一下网页源码,发现一段JavaScript代码,有一个关键类ctfs…...

Unity3D中Gfx.WaitForPresent优化方案
前言 在Unity中,Gfx.WaitForPresent占用CPU过高通常表示主线程在等待GPU完成渲染(即CPU被阻塞),这表明存在GPU瓶颈或垂直同步/帧率设置问题。以下是系统的优化方案: 对惹,这里有一个游戏开发交流小组&…...

中南大学无人机智能体的全面评估!BEDI:用于评估无人机上具身智能体的综合性基准测试
作者:Mingning Guo, Mengwei Wu, Jiarun He, Shaoxian Li, Haifeng Li, Chao Tao单位:中南大学地球科学与信息物理学院论文标题:BEDI: A Comprehensive Benchmark for Evaluating Embodied Agents on UAVs论文链接:https://arxiv.…...
【Java学习笔记】Arrays类
Arrays 类 1. 导入包:import java.util.Arrays 2. 常用方法一览表 方法描述Arrays.toString()返回数组的字符串形式Arrays.sort()排序(自然排序和定制排序)Arrays.binarySearch()通过二分搜索法进行查找(前提:数组是…...
pam_env.so模块配置解析
在PAM(Pluggable Authentication Modules)配置中, /etc/pam.d/su 文件相关配置含义如下: 配置解析 auth required pam_env.so1. 字段分解 字段值说明模块类型auth认证类模块,负责验证用户身份&am…...
生成 Git SSH 证书
🔑 1. 生成 SSH 密钥对 在终端(Windows 使用 Git Bash,Mac/Linux 使用 Terminal)执行命令: ssh-keygen -t rsa -b 4096 -C "your_emailexample.com" 参数说明: -t rsa&#x…...
使用Matplotlib创建炫酷的3D散点图:数据可视化的新维度
文章目录 基础实现代码代码解析进阶技巧1. 自定义点的大小和颜色2. 添加图例和样式美化3. 真实数据应用示例实用技巧与注意事项完整示例(带样式)应用场景在数据科学和可视化领域,三维图形能为我们提供更丰富的数据洞察。本文将手把手教你如何使用Python的Matplotlib库创建引…...

解读《网络安全法》最新修订,把握网络安全新趋势
《网络安全法》自2017年施行以来,在维护网络空间安全方面发挥了重要作用。但随着网络环境的日益复杂,网络攻击、数据泄露等事件频发,现行法律已难以完全适应新的风险挑战。 2025年3月28日,国家网信办会同相关部门起草了《网络安全…...
4. TypeScript 类型推断与类型组合
一、类型推断 (一) 什么是类型推断 TypeScript 的类型推断会根据变量、函数返回值、对象和数组的赋值和使用方式,自动确定它们的类型。 这一特性减少了显式类型注解的需要,在保持类型安全的同时简化了代码。通过分析上下文和初始值,TypeSc…...