接口请求限制自定义注解
该功能有二个文件内容,其一自定义请求限制注解,其二请求限制注解中功能的实现拦截。
其请求限制功能实习,主要是因为继承了HandlerInterceptorAdapter拦截器功能,在里面去判断是否超时与超次数。
注解文件内容
package com.annotation;
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface RequestLimit {
// 默认请求限制次数
long limit() default 10;
// 默认请求限制时间,单位 ms
long period() default 10 * 1000;
}
功能实习内容
package com.aspect;
import org.springframework.context.annotation.Configuration;
import org.springframework.stereotype.Component;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.PrintWriter;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicInteger;
@Component
//该类继承自 HandlerInterceptorAdapter,因此可以重写其方法以实现拦截器功能。
public class RequestLimitAspect extends HandlerInterceptorAdapter {
//定义一个 ConcurrentHashMap 来存储每个 IP 地址和对应的请求信息。请求信息包含请求计数和上次请求的时间。
private ConcurrentHashMap<String, RequestInfo> ipRequestInfo = new ConcurrentHashMap<>();
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
if (handler instanceof HandlerMethod) {
HandlerMethod handlerMethod = (HandlerMethod) handler;
//获取 RequestLimit 注解,检查该方法是否被标记需要限制请求。
RequestLimit requestLimit = handlerMethod.getMethodAnnotation(RequestLimit.class);
if (requestLimit == null) {
return true;
}
//从 RequestLimit 注解中获取每个 IP 最大请求次数和重置时间间隔。
long maxRequestsPerIP = requestLimit.limit();
long requestResetInterval = requestLimit.period();
//获取请求的远程 IP 地址
String ipAddress = request.getRemoteAddr();
// 获取注解所在的方法名称
String methodName = handlerMethod.getMethod().getName();
String identifier = ipAddress + "/" + methodName;
//从 ipRequestInfo 中获取该标识符对应的请求信息
RequestInfo requestInfo = ipRequestInfo.get(identifier);
if (requestInfo == null || System.currentTimeMillis() - requestInfo.getLastRequestTime() > requestResetInterval) {
// 如果 IP 地址不存在或者超过时间限制,重置请求计数
requestInfo = new RequestInfo();
ipRequestInfo.put(identifier, requestInfo);
}
if (requestInfo.getRequestCount().get() > maxRequestsPerIP) {
// 超过最大请求数,可以采取适当的措施,例如返回错误响应或记录日志
response.setStatus(429); // Too Many Requests
response.setCharacterEncoding("UTF-8");
response.setContentType("application/json; charset=utf-8");
//向响应中写入提示信息,告知用户请求次数过多,并关闭输出流。然后返回 false,阻止请求继续处理。
PrintWriter out = response.getWriter();
String body = "{\"msg\":\"请求次数过多,请稍候重试\"}";
out.write(body);
out.close();
return false;
}
requestInfo.getRequestCount().incrementAndGet();
requestInfo.setLastRequestTime(System.currentTimeMillis());
return true;
}
return true;
}
//定义一个静态内部类 RequestInfo 用于存储请求的计数和时间。
static class RequestInfo {
private AtomicInteger requestCount = new AtomicInteger(1);
private long lastRequestTime = System.currentTimeMillis();
public AtomicInteger getRequestCount() {
return requestCount;
}
public long getLastRequestTime() {
return lastRequestTime;
}
public void setLastRequestTime(long lastRequestTime) {
this.lastRequestTime = lastRequestTime;
}
}
}