限制客户端访问服务器算法
本例只是一个参考算法,楼主水平有限,如有更好的算法,欢迎指出
本例只是一个参考算法,楼主水平有限,如有更好的算法,欢迎指出
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);
}
}