本文主要是介绍使用redis计数来控制单位时间内对某接口的访问量,防止刷验证码接口之类的,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!
使用自定义注解的方式,在需要被限制访问频率的方法上加注解即可控制。
看实现方式,基于springboot,aop,redis。
新建Springboot工程,引入redis,aop。
创建注解
package com.tianyalei.annotation;import org.springframework.core.Ordered;
import org.springframework.core.annotation.Order;import java.lang.annotation.*;/*** Created by wuwf 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.tianyalei.aspect;import com.tianyalei.annotation.RequestLimit;
import com.tianyalei.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 wuwf 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.tianyalei.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.tianyalei.util;import javax.servlet.http.HttpServletRequest;
import java.net.InetAddress;
import java.net.UnknownHostException;/*** Created by admin 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;}
}
启动工程,多次访问index看看效果即可。 这篇关于使用redis计数来控制单位时间内对某接口的访问量,防止刷验证码接口之类的的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!