Springboot+Redis 实现API接口限流
添加Redis的jar包.
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
在application.yml中配置redis
spring:## Redisredis:database: 0host: 127.0.0.1port: 6379password:jedis:pool:max-active: 8max-wait: -1msmax-idle: 8min-idle: 0timeout: 2000ms
添加自定义注解
@Inherited
@Documented
@Target({ElementType.FIELD,ElementType.TYPE,ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
public @interface AccessLimit {//指定second 时间内 API请求次数int times() default 4;// 请求次数的指定时间范围 秒数(redis数据过期时间)int second() default 10;
}
编写拦截器
import com.ys.xlb.annotation.AccessLimit;
import com.ys.xlb.bean.Code;
import com.ys.xlb.exception.GlobalException;
import com.ys.xlb.utils.IpUtils;
import com.ys.xlb.utils.RequestUtils;
import com.ys.xlb.utils.ResultUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.lang.reflect.Method;
import java.util.concurrent.TimeUnit;/*** @ClassName AccessLimitInterceptor* @description: API请求限流拦截器* @time 2019-04-20 11:08**/
@Slf4j
@Component
public class AccessLimitInterceptor implements HandlerInterceptor {@Resourceprivate RedisTemplate<String, Integer> redisTemplate;@Overridepublic boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {try{// Handler 是否为 HandlerMethod 实例if(handler instanceof HandlerMethod){// 强转HandlerMethod handlerMethod = (HandlerMethod) handler;// 获取方法Method method = handlerMethod.getMethod();// 是否有AccessLimit注解if(!method.isAnnotationPresent(AccessLimit.class)){return true;}// 获取注解内容信息AccessLimit accessLimit = method.getAnnotation(AccessLimit.class);if(accessLimit == null){return true;}int times = accessLimit.times();//请求次数int second = accessLimit.second();//请求时间范围//根据 IP + API 限流String key = IpUtils.getIpAddr(request) + request.getRequestURI();//根据key获取已请求次数Integer maxTimes = redisTemplate.opsForValue().get(key);if(maxTimes == null){//set时一定要加过期时间redisTemplate.opsForValue().set(key, 1, second, TimeUnit.SECONDS);}else if(maxTimes < times){redisTemplate.opsForValue().set(key, maxTimes+1, second, TimeUnit.SECONDS);}else{// 30405 API_REQUEST_TOO_MUCH 请求过于频繁RequestUtils.out(response, ResultUtils.error(Code.API_REQUEST_TOO_MUCH));return false;}}}catch (Exception e){log.error("API请求限流拦截异常,请检查Redis是否开启!",e);throw new GlobalException(Code.BAD_REQUEST,e.getMessage());}return true;}@Overridepublic void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {}@Overridepublic void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {}
}
方法中的IP工具类方法
/*** IpUtils工具类方法* 获取真实的ip地址* @param request* @return*/public static String getIpAddr(HttpServletRequest request) {String ip = request.getHeader("X-Forwarded-For");if(org.apache.commons.lang.StringUtils.isNotEmpty(ip) && !"unKnown".equalsIgnoreCase(ip)){//多次反向代理后会有多个ip值,第一个ip才是真实ipint index = ip.indexOf(",");if(index != -1){return ip.substring(0,index);}else{return ip;}}ip = request.getHeader("X-Real-IP");if(org.apache.commons.lang.StringUtils.isNotEmpty(ip) && !"unKnown".equalsIgnoreCase(ip)){return ip;}return request.getRemoteAddr();}
RequestUtils.out()方法
/*** @Title: out* @Description: response输出JSON数据* @param response : 响应请求* @param object: object* @return void**/public static void out(ServletResponse response, Object object){PrintWriter out = null;try {response.setContentType("application/json;charset=UTF-8");response.setCharacterEncoding("UTF-8");out = response.getWriter();out.println(JSONObject.fromObject(resultMap).toString());} catch (Exception e) {log.error("输出JSON报错!"+e);}finally{if(null != out){out.flush();out.close();}}}
配置拦截器
@Configuration
public class ApplicationConfig implements WebMvcConfigurer {//这里需要注入拦截器 否则无法获取到拦截器注入的RedisTemplate<String, Integer> redisTemplate; @Beanpublic AccessLimitInterceptor accessLimitInterceptor(){return new AccessLimitInterceptor();}/*** 配置拦截器* @author lance* @param registry*/@Overridepublic void addInterceptors(InterceptorRegistry registry) {registry.addInterceptor(new LoginInterceptor()).addPathPatterns("/**").excludePathPatterns("/static/**","/login.html","/user/login");//API限流拦截registry.addInterceptor(accessLimitInterceptor()).addPathPatterns("/**").excludePathPatterns("/static/**","/login.html");}
}
配置拦截器的类中必须先注入这个拦截器否则无法获取到拦截器注入的RedisTemplate<String, Integer> redisTemplate
使用注解
/*** @Title: selectAll* @Description: 查询文章信息**/@AccessLimit(times = 5)@RequestMapping(value = "selectAll" , method = {RequestMethod.GET,RequestMethod.POST})//GetMapping(value = "selectAll")public ResultBody selectAll(Article article) {return articleService.selectAll(article);}
请求测试
时间间隔为默认的10s, 10s内请求第6次出现此返回值,完成.
参考博客:
https://blog.csdn.net/zrg523/article/details/82185088
Springboot+Redis 实现API接口限流相关推荐
- Springboot 整合 Current-Limiting 实现接口限流
该篇文章内容: 1.实现标题中提到的接口限流 2.使用压测工具jmeter给大家展现验证效果 第一部分,代码的实现 首先是导入依赖包: <dependency><groupId> ...
- 用令牌桶算法完成API接口限流
这是张富涛的第15篇原创 用令牌桶算法完成API接口限流 本文介绍了"令牌桶算法",和使用lua+redis实现基于令牌桶算法的限流. 1. 限流需求的产生背景 软件开发时偶尔会面 ...
- api接口限流 防止恶意刷接口
api限流的场景 限流的需求出现在许多常见的场景中 1.秒杀活动,有人使用软件恶意刷单抢货,需要限流防止机器参与活动 2.某api被各式各样系统广泛调用,严重消耗网络.内存等资源,需要合理限流 3.淘 ...
- redis rua解决库存问题_库存秒杀问题-redis解决方案- 接口限流
/** * Created by PhpStorm. * redis 销量超卖秒杀解决方案 * redis 文档:http://doc.redisfans.com/ * ab -n 10000 -c ...
- 【Dnc.Api.Throttle】适用于.Net Core WebApi接口限流框架
Dnc.Api.Throttle 适用于Dot Net Core的WebApi接口限流框架 使用Dnc.Api.Throttle可以使您轻松实现WebApi接口的限流管理.Dnc.Api.Thr ...
- 轻松两步,我在 SpringBoot 服务上实现了接口限流
点击上方蓝色"方志朋",选择"设为星标" 回复"666"获取独家整理的学习资料! Sentinel是阿里巴巴开源的限流器熔断器,并且带有可视 ...
- Redis做接口限流
Redis 除了做缓存,还能干很多很多事情:分布式锁.限流.处理请求接口幂等性...太多太多了-,今天想和小伙伴们聊聊用 Redis 处理接口限流. 1. 准备工作 首先我们创建一个 Spring B ...
- Redis 做接口限流
Redis 除了做缓存,还能干很多很多事情:分布式锁.限流.处理请求接口幂等性...太多太多了- 今天想和小伙伴们聊聊用 Redis 处理接口限流,这也是最近的 TienChin 项目涉及到这个知识点 ...
- Hystrix面试 - 深入 Hystrix 线程池隔离与接口限流
Hystrix面试 - 深入 Hystrix 线程池隔离与接口限流 前面讲了 Hystrix 的 request cache 请求缓存.fallback 优雅降级.circuit breaker 断路 ...
最新文章
- js:appendChild、insertBefore和insertAfter
- 深入浅出ThreadLocal,你会吗?
- 深度学习奠基人特伦斯:美国学界已经找到了解释人工智能“黑盒子”的方法...
- 'eval' is null or not an object
- freebsd重启网卡命令
- Mysql Select 语句中实现的判断
- 结构体 CString QString 成员赋值出错
- NYOJ 1066 CO-PRIME(数论)
- 脚本检测CDN节点资源是否与源站资源一致
- python selenium爬虫_详解基于python +Selenium的爬虫
- php 数组是否属于迭代器,数组的迭代器属性Iterator介绍
- GraphQL实战经验和性能问题的解决方案
- sql简介_SQL表简介
- python检测excel是否打开_Python判断远程服务器上Excel文件是否被人打开的方法_学领未来...
- 实验二-软件项目管理的直观感受
- 从 Codable 到 Swift 元编程
- python编写关不掉的流氓表白软件——快去找你爱的他表白吧
- spark outer join push down filter rule(spark 外连接中的下推规则)
- 《Java SE实战指南》10-01:特性修饰符概述
- 二、Tools实用工具-FinalShell 纯国产可同步的ssh+ftp工具
热门文章
- DTOJ4360. 魔法卡片(magic)
- 【第十四届蓝桥杯】第三期官方校内模拟赛B组C++题解(已修正完毕,均可AC100%)
- 一套POS管理系统包括哪些
- 半高领水貂绒打底衫有多高级?兼具温度与风度,穿衣显瘦,还能玩转穿搭法则!...
- QQ四国军棋刷分软件--思路
- 六种常见系统架构 —— 进阶篇
- HTML——表格标签
- ios android跨服务器,《大话西游》手游_iOS安卓跨系统角色转移功能介绍_《大话西游》手游官网...
- Word2003入门动画教程46:用“碎片”复制或移动文章
- css怎么做倒影虚化,5分钟让你掌握css3阴影、倒影、渐变小技巧!