/**
* 接口限流
* 同一个接口10s内请求超过5次进行限流
* Created by PeakGao on 2023/3/2.
*/
public class AccessLimitIntercept extends BaseController {
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, int count, int second) throws InterruptedException, IOException {
//文章搜索则不进行限流,如需部分接口地址限流可自定义注解实现
// 拼接redis key = IP + Api限流
String prefix = Constant.REDIS_KEY_PREFIX + Constant.RATE_LIMIT;
String key = ipUtils.getIpAddr(request) + request.getRequestURI();
// 获取redis的value
Integer maxTimes = null;
Object value = redisUtil.get(prefix+key);
if (value != null) {
maxTimes = (Integer) value;
}
if (maxTimes == null) {
// 如果redis中没有该ip对应的时间则表示第一次调用,保存key到redis
redisUtil.set(Constant.REDIS_KEY_PREFIX + Constant.RATE_LIMIT, key, 1, second);
} else if (maxTimes < count) {
// 如果redis中的时间比注解上的时间小则表示可以允许访问,这是修改redis的value时间
redisUtil.set(Constant.REDIS_KEY_PREFIX + Constant.RATE_LIMIT, key, maxTimes + 1, second);
} else {
// 请求过于频繁
output(response, "{\"code\":\"8002\",\"message\":\"请求过于频繁,请稍后再试\"}");
throw new RuntimeException("API请求限流拦截启动,当前接口:【" + key + "】请求过于频繁");
}
return true;
}
public void output(HttpServletResponse response, String msg) throws IOException {
response.setContentType("application/json;charset=UTF-8");
ServletOutputStream outputStream = null;
try {
outputStream = response.getOutputStream();
outputStream.write(msg.getBytes(StandardCharsets.UTF_8));
} catch (IOException e) {
e.printStackTrace();
} finally {
if (ObjectUtils.isNotEmpty(outputStream)) {
outputStream.flush();
outputStream.close();
}
}
}
}