限制客户端访问服务器算法

限制客户端访问服务器算法
本例只是一个参考算法,楼主水平有限,如有更好的算法,欢迎指出

Map 仅为了实现这个算法


import java.util.HashMap;
import java.util.Map;

import javax.servlet.http.HttpServletRequest;

/**
 * 默认 即  12小时内,最多有10个ip访问,每个ip最大允许访问100次,每个ip连续两次访问需要间隔10分钟
 */
public class RequestLimit {
	//允许访问  ip 的数量,默认10,即 时间间隔 内,允许10个ip访问
	private final static long ipNumber = 10;
	//时间间隔内 允许访问ip 最大访问次数,默认100
	private final static long ipCount = 100;
	//连续两次访问之间,需要间隔多长时间,单位毫秒,默认10分钟
	private final static long ipTimeLimit = 600000;
	//ip 时间间隔 隔断,单位为分钟,默认是12小时
	private final static long ipTime = 720;

	private static final Map<String, Long> limitTemplate = new HashMap<String, Long>();

	/**
	 * IP访问限制算法
	 * @param request
	 * @param method 访问的具体资源
	 * @throws RequestLimitException
	 */
	public synchronized static void requestLimit(HttpServletRequest request, String method) throws RequestLimitException {
		try {
			//判断当前是否超过  ip 时间间隔 隔断
			Long ipTime = limitTemplate.get("ipTime");
			if (isNull(ipTime)) {
				limitTemplate.put("ipTime", System.currentTimeMillis());
			} else {
				if (System.currentTimeMillis() - ipTime > RequestLimit.ipTime * 60000) {
					limitTemplate.clear();
					limitTemplate.put("ipTime", System.currentTimeMillis());
				}
			}
			
			if (request == null) {
				throw new RequestLimitException("无法获得访问IP地址!");
			}
			String ip = getIpAddress(request);
			if (isNull(ip)) {
				throw new RequestLimitException("没有获取到您的IP地址!");
			}
			
			//判断当前ip是否在记录中
			Long ipNumberFormRedis = limitTemplate.get(method + "_ipTime_" + ip);
			if (isNull(ipNumberFormRedis)) { //当前ip没有在缓存中存在
				//判断已经访问的的ip数量
				Long ipNumber = limitTemplate.get(method + "_ipNumber");
				if (isNull(ipNumber)) {
					ipNumber = 0L;
				}
				if (ipNumber < RequestLimit.ipNumber) { //当前缓存的ip地址少于限制的ip
					//记录当前IP访问的时间
					limitTemplate.put(method + "_ipTime_" + ip, System.currentTimeMillis());
					//记录当前IP访问的次数
					limitTemplate.put(method + "_ipCount_" + ip, 1L);
					//记录总的访问IP数量
					limitTemplate.put(method + "_ipNumber", ++ipNumber);
				} else {
					throw new RequestLimitException("达到最大访问IP限制!");
				}
			} else { //当前ip在缓冲存在了
				//获取访问次数
				Long ipCount = limitTemplate.get(method + "_ipCount_" + ip);
				if (isNull(ipCount)) {
					ipCount = RequestLimit.ipCount;
				}
				if (RequestLimit.ipCount < ipCount) { //达到单位时间内访问最大数量
					throw new RequestLimitException("达到最大访问次数!");
				}
				//获取上次访问时间
				Long oldTime = limitTemplate.get(method + "_ipTime_" + ip);
				if (isNull(oldTime)) {
					oldTime = 0L;
				}
				if (System.currentTimeMillis() - oldTime < RequestLimit.ipTimeLimit) {
					throw new RequestLimitException("访问间隔时间过短!");
				}
				limitTemplate.put(method + "_ipCount_" + ip, ++ipCount);
				limitTemplate.put(method + "_ipTime_" + ip, System.currentTimeMillis());
			}
		} catch (RequestLimitException e) {
			throw e;
		} catch (Exception e) {
			throw new RequestLimitException("IP限制访问失败!");
		}
	}
	
	public static boolean isNull(final String str) {
		return str == null || "".equals(str) || str.trim().length() == 0
				|| "null".equals(str);
	}
	
	public static boolean isNull(final Long longNum) {
		return longNum == null;
	}
	
	public static final String getIpAddress(final HttpServletRequest request) {
		// 获取请求主机IP地址,如果通过代理进来,则透过防火墙获取真实IP地址
		String ip = request.getHeader("X-Forwarded-For");
		if (isNull(ip) || "unknown".equalsIgnoreCase(ip)) {
			if (isNull(ip) || "unknown".equalsIgnoreCase(ip)) {
				ip = request.getHeader("Proxy-Client-IP");
			}
			if (isNull(ip) || "unknown".equalsIgnoreCase(ip)) {
				ip = request.getHeader("WL-Proxy-Client-IP");
			}
			if (isNull(ip) || "unknown".equalsIgnoreCase(ip)) {
				ip = request.getHeader("HTTP_CLIENT_IP");
			}
			if (isNull(ip) || "unknown".equalsIgnoreCase(ip)) {
				ip = request.getHeader("HTTP_X_FORWARDED_FOR");
			}
			if (isNull(ip) || "unknown".equalsIgnoreCase(ip)) {
				ip = request.getRemoteAddr();
			}
			
			if ("0:0:0:0:0:0:0:1".equals(ip)) {
				ip = "127.0.0.1";
			}
		} else {
			if (ip.length() > 15) {
				String[] ips = ip.split(",");
				for (int index = 0; index < ips.length; index++) {
					String strIp = ips[index];
					if (!"unknown".equalsIgnoreCase(strIp)) {
						ip = strIp;
						break;
					}
				}
			}
		}
		return ip;
	}
}


public class RequestLimitException extends RuntimeException {

	/**
	 * 
	 */
	private static final long serialVersionUID = 2071532672799571526L;

	public RequestLimitException() {
		super("请求超出限制,请联系网络管理员!");
	}

	public RequestLimitException(String message) {
		super(message);
	}
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值