SpringBoot限制请求访问次数

news2024/11/25 12:45:53

本篇文章的主要内容是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<>();

    @Override
    public 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;
    }

    @Override
    public 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 {

    @Autowired
    private RateLimitInterceptor rateLimitInterceptor;

    @Override
    public 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 {
    @Autowired
    private 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://www.coloradmin.cn/o/1938947.html

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

相关文章

【ffmpeg入门】安装CUDA并使用gpu加速

文章目录 前言CUDACUDA是什么CUDA 的主要组成部分CUDA 的优点CUDA 的基本编程模型安装CUDA ffmpeg使用gpu加速为什么需要使用gpu加速1. 提高处理速度2. 减少 CPU 负载3. 提高实时处理能力4. 支持高分辨率和复杂编码格式5. 提供更好的可扩展性6. 提高能效 ffmpeg使用gpu加速常用…

在项目中加入 husky + lint-staged + eslint,代码检测格式化

背景 由于日常工作的多人协作中&#xff0c;会因为个人代码编写风格导致代码在不同人电脑上&#xff0c;会有异常代码格式的提示&#xff0c;为了解决这个小问题&#xff0c;我们可以使用 husky lint-staged 来对代码进行一定程度上的格式化&#xff0c;使格式风格统一&#x…

初谈Linux信号-=-信号的产生

文章目录 概述从生活角度理解信号Linux中信号信号常见的处理方式理解信号的发送与保存 信号的产生core、term区别 概述 从生活角度理解信号 你在网上买了很多件商品&#xff0c;再等待不同商品快递的到来。但即便快递没有到来&#xff0c;你也知道快递来临时&#xff0c; 你该…

【 DHT11 温湿度传感器】使用STC89C51读取发送到串口、通过时序图编写C语言

文章目录 DHT11 温湿度传感器概述接线数据传送通讯过程时序图检测模块是否存在 代码实现总结对tmp tmp << 1;的理解对sendByte(datas[0]/10 0x30);的理解 DHT11 温湿度传感器 使用80C51单片机通过读取HDT11温湿度传感的数据&#xff0c;发送到串口。 通过时序图编写相应…

Windows下lapack的编译

文章目录 LAPACK库LAPACK库的地址LAPACK库的安装和编译 LAPACK库 LAPACK&#xff08;Linear Algebra PACKage&#xff09;库&#xff0c;是用Fortran语言编写的线性代数计算库&#xff0c;包含线性方程组求解&#xff08;AXb&#xff09;、矩阵分解、矩阵求逆、求矩阵特征值、…

javac详解 idea maven内部编译原理 自制编译器

起因 不知道大家在开发中&#xff0c;有没有过下面这些疑问。有的话&#xff0c;今天就一次解答清楚。 如何使用javac命令编译一个项目&#xff1f;java或者javac的一些参数到底有什么用&#xff1f;idea或者maven是如何编译java项目的&#xff1f;&#xff08;你可能猜测底层…

4核16G服务器支持多少人?4C16G服务器性能测评

租赁4核16G服务器费用&#xff0c;目前4核16G服务器10M带宽配置70元1个月、210元3个月&#xff0c;那么能如何呢&#xff1f;配置为ECS经济型e实例4核16G、按固定带宽10Mbs、100GB ESSD Entry系统盘。 那么问题来了&#xff0c;4C16G10M带宽的云服务器可以支持多少人同时在线&…

【2024最新华为OD-C/D卷试题汇总】[支持在线评测] LYA的生日派对座位安排(200分) - 三语言AC题解(Python/Java/Cpp)

🍭 大家好这里是清隆学长 ,一枚热爱算法的程序员 ✨ 本系列打算持续跟新华为OD-C/D卷的三语言AC题解 💻 ACM银牌🥈| 多次AK大厂笔试 | 编程一对一辅导 👏 感谢大家的订阅➕ 和 喜欢💗 🍿 最新华为OD机试D卷目录,全、新、准,题目覆盖率达 95% 以上,支持题目在线…

原神运行闪退报错怎么办解决办法 crossover24运行exe游戏程序错误没反应

对于Mac用户来说&#xff0c;能够在Mac上体验Windows游戏是一种极大的便利。然而&#xff0c;当尝试运行热门游戏《原神》时&#xff0c;一些用户可能会遇到闪退或报错的问题。这不仅影响了游戏体验&#xff0c;也让人倍感挫败。幸运的是&#xff0c;有多种方法可以帮助解决这些…

优化德育评估流程:智慧职校的考核类型设置功能

智慧职校德育管理系统的引入标志着教育领域向着更加智能化、高效化方向迈进的重要一步。其中&#xff0c;考核类型设置功能作为系统的核心模块之一&#xff0c;扮演着不可或缺的角色。这一功能的创新之处在于它赋予了学校前所未有的灵活性和自主权&#xff0c;让教育者能够根据…

PyTorch的自动微分模块【含梯度基本数学原理详解】

文章目录 1、简介1.1、基本概念1.2、基本原理1.2.1、自动微分1.2.2、梯度1.2.3、梯度求导1.2.4、梯度下降法1.2.5、张量梯度举例 1.3、Autograd的高级功能 2、梯度基本计算2.1、单标量梯度2.2、单向量梯度的计算2.3、多标量梯度计算2.4、多向量梯度计算 3、控制梯度计算4、累计…

【香橙派开发板测试】:在黑科技Orange Pi AIpro部署YOLOv8深度学习纤维分割检测模型

文章目录 &#x1f680;&#x1f680;&#x1f680;前言一、1️⃣ Orange Pi AIpro开发板相关介绍1.1 &#x1f393; 核心配置1.2 ✨开发板接口详情图1.3 ⭐️开箱展示 二、2️⃣配置开发板详细教程2.1 &#x1f393; 烧录镜像系统2.2 ✨配置网络2.3 ⭐️使用SSH连接主板 三、…

KAFKA搭建教程

KAFKA搭建教程 期待您的关注 KAFKA学习笔记 帮助更多人 目录 KAFKA搭建教程 1.下载Kafka并解压 2.添加环境变量 3.修改 server.properties 文件 4.将kafka复制到其它节点 5.修改node1、node2节点的broker.id 6.将master的环境变量同步到node1、 node2 7.启动zookeeper…

网络需求实验报告

拓扑图 需求 1、通过DHCP服务&#xff0c;给PC4和PC5分配IP地址、网关、掩码、DNS服务器IP地址 2、Client-1要求手工配置IP地址&#xff0c;为192.168.1.1, c 3、telnet客户端可以远程登录telnet服务器进行设备管理&#xff0c;并成功修改telnet服务器的名字为123 &#xff0c…

Dev—c++小熊猫6.7.5免费下载攻略

点击蓝字 关注我们 今天我来给大家分享一个Dev—c小熊猫6.7.5免费下载攻略&#xff0c;内容如下 1. https://gitee.com/royqh1979/Dev-CPP/releases/tag/v6.7.5 点进这一个官网&#xff0c;一直往下滑&#xff0c;找到第三个选项&#xff0c;把它下载下来。 2. 安装时一些选择…

phpstorm无法实现代码反向追踪 字体变黄(Ctrl+鼠标左键向上一级追踪)问题解决

方法一、.将项目里面的.idea文件删除掉&#xff0c;重新进入phpstorm&#xff0c;这个时候会重新对项目进行编制索引等操作&#xff0c;就会神奇的发现&#xff0c;可以正常追踪了。 当方法一不行时&#xff0c;可以使用方法二 方法二、File->invalidate Caches 去除缓存

Android中Activity生命周期详解

目录 一 典型情况二 异常情况2.1 系统配置改变2.2 系统资源不足kill掉低优先级activity Activity是四大组件之一&#xff0c;也是接触的最多的&#xff0c;一般来说Activity经常是与用户交互的界面。 一 典型情况 先看下google官网&#xff0c;其实已经很清楚了 再来个总结 …

分享一个好用的AI 动漫图片工具 - AI Anime Generator,输入文字,1分钟生成动漫图片_AI绘画工具

使用AI绘画工具&#xff0c;1分钟生成动漫图片-AI Anime Generator 分享一个AI生成动漫图片的网站。输入prompt&#xff0c;即可一键自动生成AI动漫图片。 网站名称&#xff1a;AI Anime Generator 工具地址&#xff1a;https://aianimegenerator.top 网站界面比较简洁&…

AQS和ReentrantLock源码剖析

AbstratQuenedSynchronizer抽象队列同步器 一. 简单理解 源码讲解视频 博客 核心参数 变量state &#xff1a;没加锁state0&#xff0c;加锁state1加锁线程&#xff1a;CAS 设置state1 加锁过程 尝试state的值由0变为1&#xff0c;如果发现state的值已经不为0了而是1&am…

C语言图书馆管理系统

以下是系统部分页面 以下是部分源码&#xff0c;需要源码的私信 #include<stdio.h> #include<stdlib.h> #include <string.h> #include<malloc.h>typedef struct {char student_name[100];char student_number[100];char password[100];int total_bor…