本功能的基本思想就是全局增加一个过滤器filter,,如果在指定设置时间内超过请求次数,就进行拦截。目的是为了防止有人恶意侵占资源,导致正常的请求无法响应。以下只是最简单的实现方式,需要的话可以自行拓展。
1.建立四个类
AccessStatus.java
CommonService.java
FrequentAccessControlFilter.java
FrequentAccessController.java
2.AccessStatus.java类
package com.daxiang;
public class AccessStatus {
//初次请求时间
private long lastTime;
//请求计数
private int count;
//是否已经处理
private boolean isProcessed;
public AccessStatus(){
this.lastTime = System.currentTimeMillis();
this.count = 1;
}
//getter/setter省略
}
3.FrequentAccessController.java类
package com.daxiang;
import java.util.LinkedHashMap;
import javax.servlet.http.HttpServletRequest;
public class FrequentAccessController {
private static final LinkedHashMap<String, AccessStatus> accessMap = new LinkedHashMap<>();
// 限制时间 = 1000(毫秒)
private int timeInterval=1000 ;
// 开放时间 = 5000(毫秒)
private int waitTime=5000 ;
// 在限制时间内的请求的次数 = 50
private int maxReq=50;
public boolean isFrequentAccess(HttpServletRequest request) {
// key 用token和url表示
String key = request.getRequestURL().toString();
key=key + ( request.getHeader("TK_AUTHEN_TOKEN"));
AccessStatus status;
long currTime = System.currentTimeMillis();
if (accessMap.containsKey(key)) {
status = accessMap.get(key);
if (currTime - status.getLastTime() < timeInterval) {
int count = status.getCount();
if (count > maxReq) {
return true;
} else {
count = count + 1;
status.setCount(count);
}
} else {
if (currTime - status.getLastTime() > waitTime) {
accessMap.remove(key);
}
} else {
accessMap.put(key, new AccessStatus());
}
return false;
}
public static LinkedHashMap<String, AccessStatus> getAccessMap() {
return accessMap;
}
public int getMaxReq() {
return maxReq;
}
public void setMaxReq(int maxReq) {
this.maxReq = maxReq;
}
public int getTimeInterval() {
return timeInterval;
}
public void setTimeInterval(int timeInterval) {
this.timeInterval = timeInterval;
}
public int getWaitTime() {
return waitTime;
}
public void setWaitTime(int waitTime) {
this.waitTime = waitTime;
}
}
4. FrequentAccessControlFilter.java类
package com.daxiang;
import java.io.IOException;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
public class FrequentAccessControlFilter implements Filter {
private final static FrequentAccessController frequentAccessControl = new FrequentAccessController();
// 拦截的请求方式 只拦截post请求(想拦截其他的请求方式可以自行添加)
private final static String methodName="POST";
@Override
public void destroy() {
}
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain)
throws IOException, ServletException {
HttpServletRequest request = (HttpServletRequest) servletRequest;
HttpServletResponse response = (HttpServletResponse) servletResponse;
if (frequentAccessControl.isFrequentAccess(request) && methodName.equals(request.getMethod())) {
response.setHeader("msg", "Too frequent requests");
response.sendError(403);
return;
} else {
filterChain.doFilter(servletRequest, servletResponse);
}
}
@Override
public void init(FilterConfig filterConfig) throws ServletException {
}
}
5. CommonService.java类
package com.daxiang;
import java.util.LinkedHashMap;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Service;
@Service("commonService")
public class CommonService {
// 防止内存占用过多 每10分钟清除一次内存
@Scheduled(cron="0 0/10 * * * ?")
public void destoryDosFilter(){
LinkedHashMap< String, AccessStatus> map=FrequentAccessController.getAccessMap();
map.clear();
}
}