SpringBoot限制请求访问次数

本篇文章的主要内容是SpringBoot怎么限制请求访问次数。
当我们的服务端程序部署到服务器上后,就要考虑很多关于安全的问题。总会有坏人来攻击你的服务,比如说会窃取你的数据或者给你的服务器上强度。关于给服务器上强度,往往就有高强度给服务器发送请求这个方法。所以我们就要限制请求的访问次数。
有以下几种方法:

1. 使用拦截器(interceptor)

  • 创建一个拦截器类,实现HandlerInterceptor接口
@Component
public class RateLimitInterceptor implements HandlerInterceptor {
}
  • 在拦截器中重写PreHandle方法,实现访问频率限制的逻辑
package com.game.server.interceptor;/*** @author Administrator* @date 2024/7/17 9:27* @description RateLimitInterceptor*/
import org.springframework.beans.factory.annotation.Autowired;
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.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicInteger;@Component
public class RateLimitInterceptor implements HandlerInterceptor {public static final Map<String, AtomicInteger> requestCounts = new ConcurrentHashMap<>();@Overridepublic boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {String ipAddress = request.getRemoteAddr();AtomicInteger requestCount = requestCounts.computeIfAbsent(ipAddress, k -> new AtomicInteger(0));System.out.println("当前ip:"+ipAddress+"请求次数:"+requestCount.incrementAndGet());if (requestCount.incrementAndGet() > 10) { // 限制每分钟每个IP最多10次请求response.setStatus(HttpStatus.TOO_MANY_REQUESTS.value());response.getWriter().write("请求过于频繁,请稍后再试。");
//            throw new RuntimeException("请求过于频繁,请稍后再试。");return false;}return true;}@Overridepublic void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {String ipAddress = request.getRemoteAddr();AtomicInteger requestCount = requestCounts.get(ipAddress);if (requestCount != null) {requestCount.decrementAndGet();}}
}
  • 将拦截器注册到SpringMVC的拦截链中
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.WebMvcConfigurer;@Configuration
public class WebConfig implements WebMvcConfigurer {@Autowiredprivate RateLimitInterceptor rateLimitInterceptor;@Overridepublic void addInterceptors(InterceptorRegistry registry) {registry.addInterceptor(rateLimitInterceptor).addPathPatterns("/api/**");}
}

此时需注意,有可能这会导致内存泄漏,所以我们要设置一个定时器来定时释放内存:

import lombok.extern.slf4j.Slf4j;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicInteger;@Component
@Slf4j
public class RequestCounterCleaner {@Scheduled(fixedRate = 30000) // 每分钟清理一次public void cleanRequestCounts() {log.info("清理请求表内容");RateLimitInterceptor.requestCounts.clear();}
}

最后在启动文件下启动定时器:
@EnableScheduling

@SpringBootApplication
@EnableTransactionManagement
@Slf4j
@EnableAspectJAutoProxy
@EnableScheduling
@ComponentScan(basePackages = {"com.game.common","com.game.server"})
public class ServerApplication {public static void main(String[] args) {SpringApplication.run(ServerApplication.class, args);log.info("游戏后端启动");}
}

2. 使用过滤器(Filter)

  • 和上面差不多,先创建过滤器,实现“Filter"接口
  • 在过滤器中实现对请求的逻辑处理
  • 写Filter配置文件,将过滤器注册到SpringBoot的过滤链中,确保所有请求都会通过这个过滤器
  • 写定时器定时清理数据
  • 在SpringBoot请求类中启动定时器

3. 使用切面(Aspect)

大概项目目录结构如下:
在这里插入图片描述

  • 创建注解 RequestLimit:
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
@Documented
@Order(Ordered.HIGHEST_PRECEDENCE)
public @interface RequestLimit {/*** 最大访问次数*/public int maxCount() default Integer.MAX_VALUE;/*** 访问时间段*/public long timeout() default 60*1000;
}
  • 创建切面类RequestLimitAspect:
@Slf4j
@Aspect
@Component
public class RequestLimitAspect {@Autowiredprivate RedisTemplate redisTemplate;// 以下是定义切入点@Pointcut("within(@org.springframework.web.bind.annotation.RestController *) && @annotation(com.game.server.annotation.RequestLimit)")public void autoRequestLimitPointCut(){}@Before("autoRequestLimitPointCut()")public void requestLimit(final JoinPoint joinPoint) throws RequestLimitException {log.info("开始记录请求");MethodSignature signature = (MethodSignature) joinPoint.getSignature();RequestLimit requestLimit = signature.getMethod().getAnnotation(RequestLimit.class);ServletRequestAttributes requestAttributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();HttpServletRequest request = null;if (requestAttributes != null) {request = requestAttributes.getRequest();}String ip = request.getRemoteAddr();String uri = request.getRequestURI();String url = request.getRequestURL().toString();String key = "request-limit-"+url;long count = redisTemplate.opsForValue().increment(key,1);if(count == 1){redisTemplate.expire(key,requestLimit.timeout(), TimeUnit.MILLISECONDS);}if(count > requestLimit.maxCount()){String error = "HTTP请求【"+url+"】超过限制,限制次数为【"+requestLimit.maxCount()+"】,请稍后再试";log.error(error);throw new RequestLimitException(error);}}}
  • 开始切:
    加入如下注解,顺便定义参数
    在这里插入图片描述
    这样就实现了请求限制。这个切面相比于拦截器和过滤器来说跟灵活。

4. 使用限流组件

  • 用第三方库Bucket4j,Sentinel来实现限流

5. 使用API网关

  • 在微服务中可以到微服务网关实现限流。

6. 使用Nginx配置:

在Nginx中可以通过limit_req_zone和limit_req指令来实现请求限流

http {limit_req_zone $binary_remote_addr zone=one:10m rate=10r/s;server {location /api/ {limit_req zone=one burst=5 nodelay;# 其他处理逻辑}}
}

在上面的配置中:

limit_req_zone指令用于定义请求限流的地理位置和速率。$binary_remote_addr表示使用客户端的IP地址来区分不同的地理位置,zone=one表示限流区域的名称,10m表示用于存储请求状态的内存大小,rate=10r/s表示每秒允许的请求速率为10。
在location /api/中使用了limit_req指令,将请求限流应用于/api/路径的所有请求。burst=5表示同时可以处理的并发请求的最大数量,nodelay表示当超出限流时立即返回限制状态码,而不是延迟处理。
通过这样的配置,Nginx会对/api/路径下的请求进行限流,每个IP地址每秒最多只能发送10个请求,并且使用令牌桶算法进行请求处理。

这样的配置可以有效地保护后端服务器免受过多请求的影响,防止恶意攻击和负载过载。同时,Nginx的请求限流功能可用于稳定系统并提高系统的可靠性。

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

如若内容造成侵权/违法违规/事实不符,请联系瞎胡闹网进行投诉反馈,一经查实,立即删除!

相关文章

​1:1公有云能力整体输出,腾讯云“七剑”下云端

【全球云观察 &#xff5c; 科技热点关注】 曾几何时&#xff0c;云计算技术的兴起&#xff0c;为千行万业的数字化创新带来了诸多新机遇&#xff0c;同时也催生了新产业新业态新模式&#xff0c;激发出高质量发展的科技新动能。很显然&#xff0c;如今的云创新已成为高质量发…

[React 进阶系列] useSyncExternalStore hook

[React 进阶系列] useSyncExternalStore hook 前情提要&#xff0c;包括 yup 的实现在这里&#xff1a;yup 基础使用以及 jest 测试 简单的提一下&#xff0c;需要实现的功能是&#xff1a; yup schema 需要访问外部的 storage外部的 storage 是可变的React 内部也需要访问同…

VulnHub:CK00

靶场搭建 靶机下载地址&#xff1a;CK: 00 ~ VulnHub 下载后&#xff0c;在vmware中打开靶机。 修改网络配置为NAT 处理器修改为2 启动靶机 靶机ip扫描不到的解决办法 靶机开机时一直按shift或者esc直到进入GRUB界面。 按e进入编辑模式&#xff0c;找到ro&#xff0c;修…

【devops】ttyd 一个web版本的shell工具 | web版本shell工具 | web shell

一、什么是 TTYD ttyd是在web端一个简单的服务器命令行工具 类似我们在云厂商上直接ssh链接我们的服务器输入指令一样 二、安装ttyd 1、macOS Install with Homebrew: brew install ttydInstall with MacPorts: sudo port install ttyd 2、linux Binary version (recommend…

Android10.0 锁屏分析-KeyguardPatternView图案锁分析

首先一起看看下面这张图&#xff1a; 通过前面锁屏加载流程可以知道在KeyguardSecurityContainer中使用getSecurityView()根据不同的securityMode inflate出来&#xff0c;并添加到界面上的。 我们知道&#xff0c;Pattern锁所使用的layout是 R.layout.keyguard_pattern_view&a…

Mysql基础与安装

一、数据库的概念和相关的语法和规范 1、数据库的概念 数据库&#xff1a;组织&#xff0c;存储&#xff0c;管理数据的仓库。 数据库的管理系统&#xff08;DBMS&#xff09;&#xff1a;实现对数据有效组织&#xff0c;管理和存取的系统软件。 数据库的种类&#xff1a; m…

QT 多线程 QThread

继承QThread的线程 继承 QThread 是创建线程的一个普通方法。其中创建的线程只有 run() 方法在线程里的。其他类内定义的方法都在主线程内。 通过上面的图我们可以看到&#xff0c;主线程内有很多方法在主线程内&#xff0c;但是子线程&#xff0c;只有 run() 方法是在子线…

Python | Leetcode Python题解之第236题二叉树的最近公共祖先

题目&#xff1a; 题解&#xff1a; # Definition for a binary tree node. # class TreeNode: # def __init__(self, x): # self.val x # self.left None # self.right Noneclass Solution:def lowestCommonAncestor(self, root: TreeNode, p…

实战篇(十一) : 拥抱交互的三维世界:利用 Processing 和 OpenGL 实现炫彩粒子系统

🌌 拥抱交互的三维世界:利用 Processing 和 OpenGL 实现炫彩粒子系统 在现代计算机图形学中,三维粒子系统是一个激动人心的领域。它不仅可以用来模拟自然现象,如烟雾、火焰和水流,还可以用来创造出令人叹为观止的视觉效果。在这篇文章中,我们将深入探讨如何使用 Proces…

第四届中国移动“梧桐杯”大数据创新大赛正式启动报名!

“梧桐杯”大赛是中国移动面向海内外高校青年学生打造的年度大数据创新赛事&#xff0c;以“竞逐数海&#xff0c;领航未来”为主题&#xff0c;携手政府、高校和行业企业通过比赛发掘高校优秀人才&#xff0c;孵化投资优秀项目。大赛设置“企业导师校内导师”双轨导师制&#…

Linux_线程的同步与互斥

目录 1、互斥相关概念 2、代码体现互斥重要性 3、互斥锁 3.1 初始化锁 3.2 申请、释放锁 3.3 加锁的思想 3.4 实现加锁 3.5 锁的原子性 4、线程安全 4.1 可重入函数 4.2 死锁 5、线程同步 5.1 条件变量初始化 5.2 条件变量等待队列 5.3 唤醒等待队列…

MySQL学习记录 —— 이십이 MySQL服务器文件系统(2)

文章目录 1、日志文件的整体简介2、一般、慢查询日志1、一般查询日志2、慢查询日志FILE格式TABLE格式 3、错误日志4、二进制日志5、日志维护 1、日志文件的整体简介 中继服务器的数据来源于集群中的主服务。每次做一些操作时&#xff0c;把操作保存到重做日志&#xff0c;这样崩…

JAVASE-医疗管理系统项目总结

文章目录 项目功能架构运行截图数据库设计设计模式应用单列设计模式JDBC模板模板设计模式策略模式工厂设计模式事务控制代理模式注解开发优化工厂模式 页面跳转ThreadLocal分页查询实现统计模块聊天 项目功能架构 传统的MVC架构&#xff0c;JavaFX桌面端项目&#xff0c;前端用…

R语言进行集成学习算法:随机森林

# 10.4 集成学习及随机森林 # 导入car数据集 car <- read.table("data/car.data",sep ",") # 对变量重命名 colnames(car) <- c("buy","main","doors","capacity","lug_boot","safety"…

ARM体系结构和接口技术(五)封装RCC和GPIO库

文章目录 一、RCC&#xff08;一&#xff09;思路1. 找到时钟基地址2. 找到总线的地址偏移&#xff08;1&#xff09;AHB4总线&#xff08;2&#xff09;定义不同GPIO组的使能宏函数&#xff08;3&#xff09;APB1总线&#xff08;4&#xff09;定义使能宏函数 二、GPIO&#x…

基于Java的汽车租赁管理系统设计(含文档、源码)

本篇文章论述的是基于Java的汽车租赁管理系统设计的详情介绍&#xff0c;如果对您有帮助的话&#xff0c;还请关注一下哦&#xff0c;如果有资源方面的需要可以联系我。 目录 摘 要 系统运行截图 系统总体设计 系统论文 资源下载 摘 要 近年来&#xff0c;随着改革开放…

React遍历tree结构,获取所有的id,切换自动展开对应层级

我们在做一个效果的时候&#xff0c;经常可能要设置默认展开多少的数据 1、页面效果&#xff0c;切换右侧可以下拉可切换展开的数据层级&#xff0c;仅展开两级等 2、树形的数据

C语言中常见库函数(1)——字符函数和字符串函数

文章目录 前言1.字符分类函数2.字符转换函数3.strlen的使用和模拟实现4.strcpy的使用和模拟实现5.strcat的使用和模拟实现6.strncmp的使用和模拟实现7.strncpy函数的使用8.strncat函数的使用9.strncmp函数的使用10.strstr的使用和模拟实现11.strtok函数的使用12.strerror函数的…

【文献阅读】Social Bot Detection Based on Window Strategy

Abstract 机器人发帖的目的是在不同时期宣传不同的内容&#xff0c;其发帖经常会出现异常的兴趣变化、而人类发帖的目的是表达兴趣爱好和日常生活&#xff0c;其兴趣变化相对稳定。提出了一种基于窗口策略&#xff08;BotWindow Strategy&#xff09;的社交机器人检测模型基于…

深入了解MySQL文件排序

数据准备 CREATE TABLE user_info (id bigint(20) NOT NULL AUTO_INCREMENT COMMENT ID,name varchar(20) NOT NULL COMMENT 用户名,age tinyint(4) NOT NULL DEFAULT 0 COMMENT 年龄,sex tinyint(2) NOT NULL DEFAULT 0 COMMENT 状态 0&#xff1a;男 1&#xff1a; 女,creat…