控制单位时间内接口的访问量

使用redis incr计数来控制单位时间内对某接口的访问量,防止刷验证码接口之类的。

使用自定义注解的方式,在需要被限制访问频率的方法上加注解即可控制。

看实现方式,基于springboot,aop,redis。

新建Springboot工程,引入redis,aop。

创建注解

package com.xueliang.annotation;import org.springframework.core.Ordered;
import org.springframework.core.annotation.Order;import java.lang.annotation.*;/*** Created by xueliang on 17/7/6.*/
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
@Documented
//最高优先级
@Order(Ordered.HIGHEST_PRECEDENCE)
public @interface RequestLimit {/*** 允许访问的次数*/int count() default 5;/*** 时间段,多少时间段内运行访问count次*/long time() default 60000;}

Aspect切面处理逻辑

package com.xueliang.aspect;import com.xueliang.annotation.RequestLimit;
import com.xueliang.util.HttpRequestUtil;
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.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;import javax.servlet.http.HttpServletRequest;
import java.util.concurrent.TimeUnit;/*** Created by xueliang on 17/7/6.*/
@Component
@Aspect
public class RequestLimitAspect {private final Logger logger = LoggerFactory.getLogger(getClass());@Autowiredprivate RedisTemplate<String, String> redisTemplate;@Before("execution(public * com.xueliang.controller.*.*(..)) && @annotation(limit)")public void requestLimit(JoinPoint joinpoint, RequestLimit limit) {// 接收到请求,记录请求内容ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();HttpServletRequest request = attributes.getRequest();String ip = HttpRequestUtil.getIpAddr(request);String url = request.getRequestURL().toString();String key = "req_limit_".concat(url).concat(ip);//加1后看看值long count = redisTemplate.opsForValue().increment(key, 1);//刚创建if (count == 1) {//设置1分钟过期redisTemplate.expire(key, limit.time(), TimeUnit.MILLISECONDS);}if (count > limit.count()) {logger.info("用户IP[" + ip + "]访问地址[" + url + "]超过了限定的次数[" + limit.count() + "]");throw new RuntimeException("超出访问次数限制");}}
}

获取IP的工具类

package com.xueliang.util;import javax.servlet.http.HttpServletRequest;
import java.net.InetAddress;
import java.net.UnknownHostException;/*** Created by xueliang on 17/7/6.*/
public class HttpRequestUtil {/*** 获取当前网络ip** @param request* @return*/public static String getIpAddr(HttpServletRequest request) {String ipAddress = request.getHeader("x-forwarded-for");if (ipAddress == null || ipAddress.length() == 0 || "unknown".equalsIgnoreCase(ipAddress)) {ipAddress = request.getHeader("Proxy-Client-IP");}if (ipAddress == null || ipAddress.length() == 0 || "unknown".equalsIgnoreCase(ipAddress)) {ipAddress = request.getHeader("WL-Proxy-Client-IP");}if (ipAddress == null || ipAddress.length() == 0 || "unknown".equalsIgnoreCase(ipAddress)) {ipAddress = request.getRemoteAddr();if (ipAddress.equals("127.0.0.1") || ipAddress.equals("0:0:0:0:0:0:0:1")) {//根据网卡取本机配置的IPInetAddress inet = null;try {inet = InetAddress.getLocalHost();} catch (UnknownHostException e) {e.printStackTrace();}ipAddress = inet.getHostAddress();}}//对于通过多个代理的情况,第一个IP为客户端真实IP,多个IP按照','分割if (ipAddress != null && ipAddress.length() > 15) {                                    //"***.***.***.***".length() = 15if (ipAddress.indexOf(",") > 0) {ipAddress = ipAddress.substring(0, ipAddress.indexOf(","));}}return ipAddress;}
}

通过Controller验证

@RestController
public class IndexController {@RequestLimit(count = 4)@GetMapping("/index")public Object index() {return 1;}
}

启动工程,使用jmeter多次访问index看看效果即可。

使用redis incr计数来控制单位时间内对某接口的访问量相关推荐

  1. 代码示例:使用redis计数来控制单位时间内对某接口的访问量

    控制单位时间内接口的访问量 使用redis计数来控制单位时间内对某接口的访问量,防止刷验证码接口之类的. 使用自定义注解的方式,在需要被限制访问频率的方法上加注解即可控制. 看实现方式,基于sprin ...

  2. SpringBoot+redis实现用户或者ip恶意单位时间内访问

    中心思想就是把该用户首次访问的时间和访问个数放到reds中用户每访问一次加1,先对比访问的次数是否超出,然后对比访问的时间是超出所设置的时间1.实现一个过滤器接口 package com.exam.i ...

  3. redis incr和incrBy的使用

     最近用incr和incrBy在接口里做了下埋点统计每天请求总数,这两个命令还是挺好用的,先说下这俩命令吧 注:redis后台服务是串行的单线程执行,不存在并发,即多线程调用Incr/incrby方法 ...

  4. nx set 怎么实现的原子性_【redis进阶(1)】redis的Lua脚本控制(原子性)

    [toc] 为什么要用lua 减少网络开销:本来5次网络请求的操作,可以用一个请求完成,原先5次请求的逻辑放在redis服务器上完成.使用脚本,减少了网络往返时延. 原子操作:Redis会将整个脚本作 ...

  5. 华为云PB级数据库GaussDB(for Redis)揭秘第八期:用高斯 Redis 进行计数

    本文分享自华为云社区<华为云PB级数据库GaussDB(for Redis)揭秘第八期:用高斯 Redis 进行计数>,原文作者:心机胖. 一.背景 当我们打开手机刷微博时,就要开始和各种 ...

  6. redis incr mysql_redis命令_INCR

    INCR key 将 key 中储存的数字值增一. 如果 key 不存在,那么 key 的值会先被初始化为 0 ,然后再执行 INCR 操作. 如果值包含错误的类型,或字符串类型的值不能表示为数字,那 ...

  7. 使用redis incr处理并发问题

    一.背景 最近公司某个短信接口因为没有加验证码限制被恶意调用,最好的解决办法是做在发送短信请求前做一个验证码验证通过后再调用短信接口.但是由于需要立马改动,借此使用了一下 "缓兵之计&quo ...

  8. php redis获取incr的值,Redis Incr命令

    Redis Incr命令 Redis Incr 命令将 key 中储存的数字值增一. 如果 key 不存在,那么 key 的值会先被初始化为 0 ,然后再执行 INCR 操作. 如果值包含错误的类型, ...

  9. 使用redis incr处理并发,存在死锁问题

    目录 1.项目场景: 2.问题代码 : 3.修改后的代码: 4.实战示例: 5.更新:setIfAbsent 6.再次更新:redisson 1.项目场景: 锁主要是用来实现资源共享同步,只有获取到了 ...

最新文章

  1. “老赖”罗永浩:就算“卖艺”也会还债!孙宇晨:我买!
  2. 用ggplot包画一个简单饼图
  3. 在redhat9中交叉编译nano-X nxlib和fltk
  4. 厉害了!一文看懂各大互联网支付系统整体架构
  5. 技术干货 | Native 页面下如何实现导航栏的定制化开发?
  6. 上周热点回顾(7.10-7.16)
  7. 闲聊位置之 POI数据
  8. 面试官:为什么SpringBoot的 jar 可以直接运行?
  9. 创维25TI9000工厂模式
  10. PyAudio库简介
  11. 新偶像时代:被直播重构的粉丝经济和社交平台
  12. 一款超好用的企业级URL采集软件(Msray-plus)
  13. 【iphone4s/ipad2回滚ios6.1.3】file:installer.cpp; line: 71; what:_assert(teams.empty()) 报错解决方法
  14. 使用adb命令安装apk
  15. uni-app 启动手机模拟器
  16. CISSP AIO7 学习笔记 - 第二章 资产安全 2.1-2.8小节 附送脑图
  17. 《SEO的艺术(原书第2版)》——2.6 垂直搜索引擎
  18. 汉寿计算机职业中专,汉寿县职业中等专业学校2021年有哪些专业
  19. 三维空间坐标系变换-旋转矩阵
  20. c语言程序设计基础课后习题答案,2011级C语言程序设计基础教程课后习题答案

热门文章

  1. 【NLP】中文BERT上分新技巧,多粒度信息来帮忙
  2. 【送书】联邦学习在视觉领域的应用,揭秘2020年AAAI人工智能创新应用奖获奖案例!...
  3. 【经验】新人学习写程序的第一道坎
  4. 复现经典:《统计学习方法》第 9 章 EM 算法及其推广
  5. 分享:我是怎么在github上找到优秀的仓库的?
  6. 2018到2008,10年CVPR/NIPS/ECCV/ICML顶会精选论文+代码集合资源
  7. AI圈最新深度学习量化算法!
  8. 不就是发个短信吗?这你都会?
  9. Node.js 基金会和 JS 基金会准备合并,你怎么看?
  10. System.InvalidOperationException:“线程间操作无效: 从不是创建控件“txtPortName02”的线程访问它。”...