使用 guava 实现网站某个URL限流功能
程序员文章站
2022-06-21 21:10:15
...
1.限流类
package com.leimingtech.admin.utils;
import com.google.common.util.concurrent.RateLimiter;
import com.leimingtech.core.cache.jedis.JedisUtils;
import com.leimingtech.extend.module.payment.wechat.mobile.util.MD5Util;
import lombok.extern.slf4j.Slf4j;
import javax.servlet.http.HttpServletRequest;
import java.util.Enumeration;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.TimeUnit;
/**
* Author by gjp, Date on 2019/9/23.
* 页面访问频率限制
*/
@Slf4j
public class PageRate {
public static final PageRate pageRate = new PageRate();
ConcurrentHashMap<String, RateLimiter> rateLimiterPool = new ConcurrentHashMap<String, RateLimiter>();
//每秒钟访问次数
private int RATE_NUM = 2;
private int LIMIT_DATE=1000 * 60 * 60;
public static PageRate getInstance(){
return pageRate;
}
/**
* 访问频率限制
* @param request
* @return
*/
public boolean limitReqRate(HttpServletRequest request){
boolean flag = true;
String url = request.getRequestURI();
String ip = getIpAddress(request);
StringBuffer stringBuffer = new StringBuffer(60);
stringBuffer.append(url).append("-").append(ip);
String key = "LYPT:RATE:"+MD5Util.MD5Encode(stringBuffer.toString(),"UTF-8");
//检查key值是否存在
if(JedisUtils.exists(key)){
log.info("该用户的ip地址已经被禁止访问,key={}",key);
flag = false;
}
if (rateLimiterPool.containsKey(key)) {//已经加入计数器
if (rateLimiterPool.get(key).tryAcquire(1, TimeUnit.SECONDS)) {
log.info("获取的访问权限",key);
}else {
System.out.println("超出最大访问限制 "+key);
JedisUtils.set(key,stringBuffer.toString(),LIMIT_DATE);
}
}else {
//没有加入计数器
log.info("加入访问权限列表",key);
RateLimiter rateLimiter = RateLimiter.create(RATE_NUM);
rateLimiterPool.put(key, rateLimiter);
}
return flag;
}
/**
* 获取ip地址
* @param request
* @return
*/
public String getIpAddress(HttpServletRequest request) {
String ip = request.getHeader("x-forwarded-for");
if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
ip = request.getHeader("Proxy-Client-IP");
}
if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
ip = request.getHeader("WL-Proxy-Client-IP");
}
if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
ip = request.getHeader("HTTP_CLIENT_IP");
}
if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
ip = request.getHeader("HTTP_X_FORWARDED_FOR");
}
if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
ip = request.getRemoteAddr();
}
return ip;
}
/**
* 遍历限速池
* @return
*/
public String listKey(){
StringBuffer sb =new StringBuffer(100);
Enumeration<String> enu = rateLimiterPool.keys();
while (enu.hasMoreElements()){
sb.append(enu.nextElement()).append("-");
}
return sb.toString();
}
/**
* 删除 key
* @param key
* @return
*/
public boolean delByKey(final String key){
RateLimiter limiter = rateLimiterPool.remove(key);
boolean flag =false;
if(null !=limiter){
flag = true;
}
return flag;
}
/**
*
* @param key
* @param num
* @return
*/
public RateLimiter put(String key,String num){
RateLimiter rateLimiter = RateLimiter.create(Double.parseDouble(num));
return rateLimiterPool.put(key,rateLimiter);
}
/**
*
* @param key
* @param rateLimiter
* @return
*/
public RateLimiter put(String key,RateLimiter rateLimiter){
return rateLimiterPool.put(key,rateLimiter);
}
}
2.使用限流方法
@RequestMapping(value = "/login")
public String login(Model model,HttpServletRequest httpServletRequest) {
//开启限流功能
boolean rateFlag = PageRate.getInstance().limitReqRate(httpServletRequest);
if(!rateFlag){
return "/index/rate";
}
try {
Subject subject = SecurityUtils.getSubject();
if (subject.isAuthenticated()) {
return "redirect:/";
}
return "/index/login";
} catch (Exception e) {
log.error("跳转登录页面异常:", e);
}
return null;
}