当前位置: 首页 > news >正文

限制API接口访问速率

文章目录

  • 依赖
  • 注解
  • aop
  • helper
  • Test

免责声明:本人无意侵权,奈何找不到原文作者,也找不到网址,于是自己记录一下,如果有侵权之嫌,请联系我删除文章

依赖

  <!-- https://mvnrepository.com/artifact/com.google.guava/guava --><dependency><groupId>com.google.guava</groupId><artifactId>guava</artifactId><version>32.1.3-jre</version></dependency>

注解

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;@Target(value = ElementType.METHOD)
@Retention(value = RetentionPolicy.RUNTIME)
public @interface RateConfigAnno {String limitType();double limitCount() default 5d;
}

aop

import cn.hutool.core.thread.ThreadUtil;
import com.alibaba.fastjson2.JSONObject;
import com.google.common.util.concurrent.RateLimiter;
import com.tjbchtyw.tjflowcontrol.annocation.RateConfigAnno;
import com.tjbchtyw.tjflowcontrol.helper.RateLimitHelper;
import jakarta.servlet.ServletOutputStream;
import jakarta.servlet.http.HttpServletResponse;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;import java.io.IOException;
import java.lang.reflect.Method;
import java.nio.charset.StandardCharsets;
import java.util.Objects;@Aspect
@Component
public class GuavaLimitAop {private static final Logger logger = LoggerFactory.getLogger(GuavaLimitAop.class);@Before("@annotation(com.tjbchtyw.tjflowcontrol.annocation.RateConfigAnno)")public void limit(JoinPoint joinPoint) {//1、获取当前的调用方法Method currentMethod = getCurrentMethod(joinPoint);if (Objects.isNull(currentMethod)) {return;}//2、从方法注解定义上获取限流的类型String limitType = currentMethod.getAnnotation(RateConfigAnno.class).limitType();double limitCount = currentMethod.getAnnotation(RateConfigAnno.class).limitCount();//使用guava的令牌桶算法获取一个令牌,获取不到先等待RateLimiter rateLimiter = RateLimitHelper.getRateLimiter(limitType, limitCount);//  boolean b =true;boolean pass = rateLimiter.tryAcquire();if (pass) {System.out.println("获取到令牌");}else {//重试 仅测试用 有优化方案可以放在评论区for (int i = 0; i < 5; i++) {ThreadUtil.safeSleep(1000);System.out.println("第" + (i + 1)  + "次获取令牌");if(rateLimiter.tryAcquire()) break;if(i == 4){System.out.println("在第" + (i + 1) +"次后未获取到令牌 开始限流");HttpServletResponse resp = ((ServletRequestAttributes)RequestContextHolder.getRequestAttributes()).getResponse();JSONObject jsonObject=new JSONObject();jsonObject.put("success",false);jsonObject.put("msg","限流中");try {output(resp, jsonObject.toJSONString());}catch (Exception e){logger.error("error,e:{}",e);}}}}}private Method getCurrentMethod(JoinPoint joinPoint) {Method[] methods = joinPoint.getTarget().getClass().getMethods();Method target = null;for (Method method : methods) {if (method.getName().equals(joinPoint.getSignature().getName())) {target = method;break;}}return target;}public void output(HttpServletResponse response, String msg) throws IOException {response.setContentType("application/json;charset=UTF-8");ServletOutputStream outputStream = null;try {outputStream = response.getOutputStream();outputStream.write(msg.getBytes(StandardCharsets.UTF_8));} catch (IOException e) {e.printStackTrace();} finally {outputStream.flush();outputStream.close();}}
}

helper

import com.google.common.util.concurrent.RateLimiter;import java.util.HashMap;
import java.util.Map;public class RateLimitHelper {private RateLimitHelper(){}private static final Map<String,RateLimiter> rateMap = new HashMap<>();public static RateLimiter getRateLimiter(String limitType, double limitCount ){RateLimiter rateLimiter = rateMap.get(limitType);if(rateLimiter == null){rateLimiter = RateLimiter.create(limitCount);rateMap.put(limitType,rateLimiter);}return rateLimiter;}}

Test

@RestController@Tag(name = "测试Controller", description = "这是描述")@RequestMapping("/pred-api")public class FlowController {@AutowiredFlowContext flowContext;@PostMapping("/pdf/test")//Count 限制次数@RateConfigAnno(limitType = "makePdf",limitCount = 15)@Operation(summary = "限流接口")public String flowCont(@Parameter(name = "pdfParam", description = "参数对象,type标识执行不同的策略") @RequestBody Param Param) {return "test";}}

相关文章:

  • 大语言模型系列-BERT
  • DNS - 全家桶(114 DNS、阿里DNS、百度DNS 、360 DNS、Google DNS)
  • 图像处理:孤立点的检测
  • rust获取本地ip地址的方法
  • 基于小波多普勒变换的回波信号检测matlab仿真
  • 技术进化与经济互动的深刻洞察——《技术的本质》读书笔记
  • 2000W双向逆变器介绍
  • 运动型蓝牙耳机推荐哪款?2024运动耳机排行榜最新
  • CentOS 7.9 安装图解
  • ReactNative中样式与布局的书写
  • 架设一台NFS服务器,并按照以下要求配置
  • VR远程的实现
  • MySQL Update语句一个非常经典的“坑”
  • Pure-admin框架 Pure-table中获取所选中的内容的信息
  • ARM的一些基础知识
  • axios请求、和返回数据拦截,统一请求报错提示_012
  • Create React App 使用
  • iOS高仿微信项目、阴影圆角渐变色效果、卡片动画、波浪动画、路由框架等源码...
  • iOS筛选菜单、分段选择器、导航栏、悬浮窗、转场动画、启动视频等源码
  • springboot_database项目介绍
  • 持续集成与持续部署宝典Part 2:创建持续集成流水线
  • 初探 Vue 生命周期和钩子函数
  • 工作中总结前端开发流程--vue项目
  • 如何用Ubuntu和Xen来设置Kubernetes?
  • 深度学习入门:10门免费线上课程推荐
  • 双管齐下,VMware的容器新战略
  • 网络应用优化——时延与带宽
  • 文本多行溢出显示...之最后一行不到行尾的解决
  • 用 vue 组件自定义 v-model, 实现一个 Tab 组件。
  • elasticsearch-head插件安装
  • ​MPV,汽车产品里一个特殊品类的进化过程
  • ​Python 3 新特性:类型注解
  • ​一些不规范的GTID使用场景
  • #!/usr/bin/python与#!/usr/bin/env python的区别
  • (003)SlickEdit Unity的补全
  • (2022 CVPR) Unbiased Teacher v2
  • (Java数据结构)ArrayList
  • (zt)最盛行的警世狂言(爆笑)
  • (草履虫都可以看懂的)PyQt子窗口向主窗口传递参数,主窗口接收子窗口信号、参数。
  • (第9篇)大数据的的超级应用——数据挖掘-推荐系统
  • (二开)Flink 修改源码拓展 SQL 语法
  • (附源码)springboot 房产中介系统 毕业设计 312341
  • (附源码)springboot车辆管理系统 毕业设计 031034
  • (附源码)ssm失物招领系统 毕业设计 182317
  • (原創) 如何讓IE7按第二次Ctrl + Tab時,回到原來的索引標籤? (Web) (IE) (OS) (Windows)...
  • (转载)跟我一起学习VIM - The Life Changing Editor
  • .dwp和.webpart的区别
  • .netcore 如何获取系统中所有session_如何把百度推广中获取的线索(基木鱼,电话,百度商桥等)同步到企业微信或者企业CRM等企业营销系统中...
  • .NET处理HTTP请求
  • .NET下ASPX编程的几个小问题
  • .sh
  • [.net] 如何在mail的加入正文显示图片
  • [16/N]论得趣
  • [2023-年度总结]凡是过往,皆为序章
  • [AI]ChatGPT4 与 ChatGPT3.5 区别有多大