|
@@ -1,305 +1,305 @@
|
|
-package cn.com.qmth.examcloud.web.interceptor;
|
|
|
|
-
|
|
|
|
-import cn.com.qmth.examcloud.commons.util.Util;
|
|
|
|
-import cn.com.qmth.examcloud.web.actuator.ApiStatusInfo;
|
|
|
|
-import cn.com.qmth.examcloud.web.actuator.ApiStatusInfoHolder;
|
|
|
|
-import cn.com.qmth.examcloud.web.bootstrap.PropertyHolder;
|
|
|
|
-import cn.com.qmth.examcloud.web.enums.HttpServletRequestAttribute;
|
|
|
|
-import cn.com.qmth.examcloud.web.support.ApiInfo;
|
|
|
|
-import cn.com.qmth.examcloud.web.support.ServletUtil;
|
|
|
|
-import cn.com.qmth.examcloud.web.support.StatusResponse;
|
|
|
|
-import com.google.common.collect.Maps;
|
|
|
|
-import com.google.common.util.concurrent.RateLimiter;
|
|
|
|
-import com.googlecode.aviator.AviatorEvaluator;
|
|
|
|
-import org.apache.commons.lang.math.RandomUtils;
|
|
|
|
-import org.apache.commons.lang3.StringUtils;
|
|
|
|
-import org.slf4j.Logger;
|
|
|
|
-import org.slf4j.LoggerFactory;
|
|
|
|
-import org.springframework.http.HttpStatus;
|
|
|
|
-import org.springframework.web.servlet.HandlerInterceptor;
|
|
|
|
-
|
|
|
|
-import javax.servlet.http.HttpServletRequest;
|
|
|
|
-import javax.servlet.http.HttpServletResponse;
|
|
|
|
-import java.io.BufferedReader;
|
|
|
|
-import java.io.IOException;
|
|
|
|
-import java.io.InputStream;
|
|
|
|
-import java.io.InputStreamReader;
|
|
|
|
-import java.util.Map;
|
|
|
|
-import java.util.Map.Entry;
|
|
|
|
-import java.util.Properties;
|
|
|
|
-
|
|
|
|
-/**
|
|
|
|
- * API 流量限制截器
|
|
|
|
- *
|
|
|
|
- * @author WANGWEI
|
|
|
|
- * @date 2019年7月24日
|
|
|
|
- * @Copyright (c) 2018-? http://qmth.com.cn All Rights Reserved.
|
|
|
|
- */
|
|
|
|
-@Deprecated
|
|
|
|
-public class ApiFlowLimitedInterceptor implements HandlerInterceptor {
|
|
|
|
-
|
|
|
|
- private static final Logger LOG = LoggerFactory.getLogger(ApiFlowLimitedInterceptor.class);
|
|
|
|
-
|
|
|
|
- private static RateLimiter rateLimiter;
|
|
|
|
-
|
|
|
|
- private static boolean enable = false;
|
|
|
|
-
|
|
|
|
- private static int allowedRate = 0;
|
|
|
|
-
|
|
|
|
- private static int minCallRate = 0;
|
|
|
|
-
|
|
|
|
- private static Properties PROPS = new Properties();
|
|
|
|
-
|
|
|
|
- private static Map<String, RateLimiter> limiterMap = Maps.newConcurrentMap();
|
|
|
|
-
|
|
|
|
- private static Map<String, Integer> permitsPerSecondMap = Maps.newConcurrentMap();
|
|
|
|
-
|
|
|
|
- static {
|
|
|
|
- // init();
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- private static void init() {
|
|
|
|
- int permitsPerSecond = PropertyHolder.getInt("examcloud.api.permitsPerSecond", 100000);
|
|
|
|
- rateLimiter = RateLimiter.create(permitsPerSecond);
|
|
|
|
-
|
|
|
|
- enable = PropertyHolder.getBoolean("examcloud.api.flowLimited.enable", false);
|
|
|
|
- allowedRate = PropertyHolder.getInt("examcloud.api.flowLimited.allowedRate", 5);
|
|
|
|
- minCallRate = PropertyHolder.getInt("examcloud.api.flowLimited.minCallRate", 10);
|
|
|
|
-
|
|
|
|
- loadProperties();
|
|
|
|
-
|
|
|
|
- for (Entry<Object, Object> entry : PROPS.entrySet()) {
|
|
|
|
- String key = (String) entry.getKey();
|
|
|
|
- String value = (String) entry.getValue();
|
|
|
|
-
|
|
|
|
- if (key.endsWith("[S]")) {
|
|
|
|
- Integer curPermitsPerSecond = null;
|
|
|
|
- try {
|
|
|
|
- curPermitsPerSecond = Integer.parseInt(value);
|
|
|
|
- } catch (NumberFormatException e) {
|
|
|
|
- LOG.error("value invalid. key= " + key, e);
|
|
|
|
- continue;
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- if (curPermitsPerSecond < 0) {
|
|
|
|
- LOG.error("value is less than 0. key= " + key);
|
|
|
|
- continue;
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- if (curPermitsPerSecond > 10000) {
|
|
|
|
- LOG.error("value is more than 10000. key= " + key);
|
|
|
|
- continue;
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- RateLimiter curRateLimiter = RateLimiter.create(curPermitsPerSecond);
|
|
|
|
- limiterMap.put(key, curRateLimiter);
|
|
|
|
- permitsPerSecondMap.put(key, curPermitsPerSecond);
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- new Thread(new Runnable() {
|
|
|
|
- @Override
|
|
|
|
- public void run() {
|
|
|
|
-
|
|
|
|
- while (true) {
|
|
|
|
- // 3分钟
|
|
|
|
- Util.sleep(180);
|
|
|
|
-
|
|
|
|
- loadProperties();
|
|
|
|
-
|
|
|
|
- Map<String, Integer> updated = Maps.newHashMap();
|
|
|
|
-
|
|
|
|
- for (Entry<String, Integer> entry : permitsPerSecondMap.entrySet()) {
|
|
|
|
- String key = entry.getKey();
|
|
|
|
- Integer value = entry.getValue();
|
|
|
|
-
|
|
|
|
- String curValue = (String) PROPS.get(key);
|
|
|
|
- if (StringUtils.isBlank(curValue)) {
|
|
|
|
- continue;
|
|
|
|
- }
|
|
|
|
- Integer curPermitsPerSecond = null;
|
|
|
|
- try {
|
|
|
|
- curPermitsPerSecond = Integer.parseInt(curValue);
|
|
|
|
- } catch (NumberFormatException e) {
|
|
|
|
- LOG.error("value invalid. key= " + key, e);
|
|
|
|
- continue;
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- if (curPermitsPerSecond < 0) {
|
|
|
|
- LOG.error("value is less than 0. key= " + key);
|
|
|
|
- continue;
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- if (curPermitsPerSecond > 10000) {
|
|
|
|
- LOG.error("value is more than 10000. key= " + key);
|
|
|
|
- continue;
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- if (!value.equals(curPermitsPerSecond)) {
|
|
|
|
- RateLimiter curRateLimiter = limiterMap.get(key);
|
|
|
|
- curRateLimiter.setRate(curPermitsPerSecond);
|
|
|
|
- updated.put(key, curPermitsPerSecond);
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- permitsPerSecondMap.putAll(updated);
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
- }).start();
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- private synchronized static void loadProperties() {
|
|
|
|
- final String propertyPath = "limited.properties";
|
|
|
|
-
|
|
|
|
- InputStream is = ApiFlowLimitedInterceptor.class.getClassLoader().getResourceAsStream(propertyPath);
|
|
|
|
- if (is == null) {
|
|
|
|
- LOG.warn("{} is not exist!", propertyPath);
|
|
|
|
- return;
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- try (InputStreamReader isr = new InputStreamReader(is, "UTF-8");
|
|
|
|
- BufferedReader br = new BufferedReader(isr);) {
|
|
|
|
-
|
|
|
|
- Properties curProperties = new Properties();
|
|
|
|
- curProperties.load(br);
|
|
|
|
-
|
|
|
|
- PROPS.clear();
|
|
|
|
- if (curProperties.size() > 0) {
|
|
|
|
- PROPS.putAll(curProperties);
|
|
|
|
-
|
|
|
|
- LOG.info("Load api limited props size is {}", PROPS.size());
|
|
|
|
- }
|
|
|
|
- } catch (Exception e) {
|
|
|
|
- LOG.error("Load api limited config fail! " + e.getMessage(), e);
|
|
|
|
- } finally {
|
|
|
|
- try {
|
|
|
|
- is.close();
|
|
|
|
- } catch (IOException e) {
|
|
|
|
- // ignore...
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- @Override
|
|
|
|
- public boolean preHandle(HttpServletRequest request,
|
|
|
|
- HttpServletResponse response,
|
|
|
|
- Object handler) throws Exception {
|
|
|
|
- if (!enable) {
|
|
|
|
- return true;
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- boolean acquired = rateLimiter.tryAcquire();
|
|
|
|
- if (!acquired) {
|
|
|
|
- LOG.error("Api Limited, url = {}", request.getServletPath());
|
|
|
|
-
|
|
|
|
- response.setStatus(HttpStatus.SERVICE_UNAVAILABLE.value());
|
|
|
|
- ServletUtil.returnJson(new StatusResponse("503", "api limited"), response);
|
|
|
|
- return false;
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- ApiInfo apiInfo = (ApiInfo) request.getAttribute(HttpServletRequestAttribute.$_API_INFO.name());
|
|
|
|
- if (null == apiInfo) {
|
|
|
|
- return true;
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- ApiStatusInfo apiStatusInfo = null;
|
|
|
|
- try {
|
|
|
|
- apiStatusInfo = ApiStatusInfoHolder.getApiStatusInfo(apiInfo.getMapping());
|
|
|
|
- } catch (Exception e) {
|
|
|
|
- // ignore
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- if (null == apiStatusInfo) {
|
|
|
|
- return true;
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- String rateLimiterKey = apiInfo.getMapping() + "[S]";
|
|
|
|
- RateLimiter limiter = limiterMap.get(rateLimiterKey);
|
|
|
|
-
|
|
|
|
- if (null != limiter) {
|
|
|
|
- acquired = limiter.tryAcquire();
|
|
|
|
- if (!acquired) {
|
|
|
|
- LOG.error("[S] Api Limited, mapping = {}", apiInfo.getMapping());
|
|
|
|
-
|
|
|
|
- response.setStatus(HttpStatus.SERVICE_UNAVAILABLE.value());
|
|
|
|
- ServletUtil.returnJson(new StatusResponse("503", "api limited"), response);
|
|
|
|
- return false;
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- String expression = null;
|
|
|
|
- String expressionKey = apiInfo.getMapping() + "[E]";
|
|
|
|
- try {
|
|
|
|
- expression = (String) PROPS.get(expressionKey);
|
|
|
|
- } catch (Exception e) {
|
|
|
|
- LOG.error("error value. key= " + expressionKey, e);
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- if (StringUtils.isBlank(expression)) {
|
|
|
|
- return true;
|
|
|
|
- }
|
|
|
|
- expression = expression.trim();
|
|
|
|
-
|
|
|
|
- if (LOG.isDebugEnabled()) {
|
|
|
|
- LOG.debug("expression=" + expression + " ; mapping=" + apiInfo.getMapping());
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- Map<String, Object> env = Maps.newHashMap();
|
|
|
|
- env.put("mean", apiStatusInfo.getMean());
|
|
|
|
- env.put("max", apiStatusInfo.getMax());
|
|
|
|
- env.put("min", apiStatusInfo.getMin());
|
|
|
|
- env.put("meanRate", apiStatusInfo.getMeanRate());
|
|
|
|
- env.put("oneMinRate", apiStatusInfo.getOneMinuteRate());
|
|
|
|
- env.put("errPercent", apiStatusInfo.getErrorPercent());
|
|
|
|
- env.put("errMeanRate", apiStatusInfo.getErrorMeanRate());
|
|
|
|
-
|
|
|
|
- boolean limited = false;
|
|
|
|
- try {
|
|
|
|
- limited = (Boolean) AviatorEvaluator.execute(expression, env, true);
|
|
|
|
- } catch (Exception e) {
|
|
|
|
- LOG.error("Get value fail. expression= " + expression, e);
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- if (limited) {
|
|
|
|
- int random = RandomUtils.nextInt(100);
|
|
|
|
- if (random <= allowedRate) {
|
|
|
|
- double oneMinuteRate = apiStatusInfo.getOneMinuteRate();
|
|
|
|
-
|
|
|
|
- int curMinCallRate = minCallRate;
|
|
|
|
- String minCallRateKey = apiInfo.getMapping() + "[R]";
|
|
|
|
- try {
|
|
|
|
- String value = (String) PROPS.get(minCallRateKey);
|
|
|
|
- if (StringUtils.isNotBlank(value)) {
|
|
|
|
- curMinCallRate = Integer.parseInt(value.trim());
|
|
|
|
- }
|
|
|
|
- } catch (Exception e) {
|
|
|
|
- LOG.error("error value. key= " + minCallRateKey, e);
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- if (LOG.isDebugEnabled()) {
|
|
|
|
- LOG.debug("minCallRate=" + curMinCallRate + "; mapping=" + apiInfo.getMapping());
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- if (oneMinuteRate < curMinCallRate) {
|
|
|
|
- return true;
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- LOG.error("[ER] Api Limited, mapping = {}", apiInfo.getMapping());
|
|
|
|
-
|
|
|
|
- response.setStatus(HttpStatus.SERVICE_UNAVAILABLE.value());
|
|
|
|
- ServletUtil.returnJson(new StatusResponse("503", "api limited"), response);
|
|
|
|
- return false;
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- return true;
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- @Override
|
|
|
|
- public void afterCompletion(HttpServletRequest request, HttpServletResponse response,
|
|
|
|
- Object handler, Exception ex) throws Exception {
|
|
|
|
-
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
-}
|
|
|
|
|
|
+// package cn.com.qmth.examcloud.web.interceptor;
|
|
|
|
+//
|
|
|
|
+// import cn.com.qmth.examcloud.commons.util.Util;
|
|
|
|
+// import cn.com.qmth.examcloud.web.actuator.ApiStatusInfo;
|
|
|
|
+// import cn.com.qmth.examcloud.web.actuator.ApiStatusInfoHolder;
|
|
|
|
+// import cn.com.qmth.examcloud.web.bootstrap.PropertyHolder;
|
|
|
|
+// import cn.com.qmth.examcloud.web.enums.HttpServletRequestAttribute;
|
|
|
|
+// import cn.com.qmth.examcloud.web.support.ApiInfo;
|
|
|
|
+// import cn.com.qmth.examcloud.web.support.ServletUtil;
|
|
|
|
+// import cn.com.qmth.examcloud.web.support.StatusResponse;
|
|
|
|
+// import com.google.common.collect.Maps;
|
|
|
|
+// import com.google.common.util.concurrent.RateLimiter;
|
|
|
|
+// import com.googlecode.aviator.AviatorEvaluator;
|
|
|
|
+// import org.apache.commons.lang.math.RandomUtils;
|
|
|
|
+// import org.apache.commons.lang3.StringUtils;
|
|
|
|
+// import org.slf4j.Logger;
|
|
|
|
+// import org.slf4j.LoggerFactory;
|
|
|
|
+// import org.springframework.http.HttpStatus;
|
|
|
|
+// import org.springframework.web.servlet.HandlerInterceptor;
|
|
|
|
+//
|
|
|
|
+// import javax.servlet.http.HttpServletRequest;
|
|
|
|
+// import javax.servlet.http.HttpServletResponse;
|
|
|
|
+// import java.io.BufferedReader;
|
|
|
|
+// import java.io.IOException;
|
|
|
|
+// import java.io.InputStream;
|
|
|
|
+// import java.io.InputStreamReader;
|
|
|
|
+// import java.util.Map;
|
|
|
|
+// import java.util.Map.Entry;
|
|
|
|
+// import java.util.Properties;
|
|
|
|
+//
|
|
|
|
+// /**
|
|
|
|
+// * API 流量限制截器
|
|
|
|
+// *
|
|
|
|
+// * @author WANGWEI
|
|
|
|
+// * @date 2019年7月24日
|
|
|
|
+// * @Copyright (c) 2018-? http://qmth.com.cn All Rights Reserved.
|
|
|
|
+// */
|
|
|
|
+// @Deprecated
|
|
|
|
+// public class ApiFlowLimitedInterceptor implements HandlerInterceptor {
|
|
|
|
+//
|
|
|
|
+// private static final Logger LOG = LoggerFactory.getLogger(ApiFlowLimitedInterceptor.class);
|
|
|
|
+//
|
|
|
|
+// private static RateLimiter rateLimiter;
|
|
|
|
+//
|
|
|
|
+// private static boolean enable = false;
|
|
|
|
+//
|
|
|
|
+// private static int allowedRate = 0;
|
|
|
|
+//
|
|
|
|
+// private static int minCallRate = 0;
|
|
|
|
+//
|
|
|
|
+// private static Properties PROPS = new Properties();
|
|
|
|
+//
|
|
|
|
+// private static Map<String, RateLimiter> limiterMap = Maps.newConcurrentMap();
|
|
|
|
+//
|
|
|
|
+// private static Map<String, Integer> permitsPerSecondMap = Maps.newConcurrentMap();
|
|
|
|
+//
|
|
|
|
+// static {
|
|
|
|
+// // init();
|
|
|
|
+// }
|
|
|
|
+//
|
|
|
|
+// private static void init() {
|
|
|
|
+// int permitsPerSecond = PropertyHolder.getInt("examcloud.api.permitsPerSecond", 100000);
|
|
|
|
+// rateLimiter = RateLimiter.create(permitsPerSecond);
|
|
|
|
+//
|
|
|
|
+// enable = PropertyHolder.getBoolean("examcloud.api.flowLimited.enable", false);
|
|
|
|
+// allowedRate = PropertyHolder.getInt("examcloud.api.flowLimited.allowedRate", 5);
|
|
|
|
+// minCallRate = PropertyHolder.getInt("examcloud.api.flowLimited.minCallRate", 10);
|
|
|
|
+//
|
|
|
|
+// loadProperties();
|
|
|
|
+//
|
|
|
|
+// for (Entry<Object, Object> entry : PROPS.entrySet()) {
|
|
|
|
+// String key = (String) entry.getKey();
|
|
|
|
+// String value = (String) entry.getValue();
|
|
|
|
+//
|
|
|
|
+// if (key.endsWith("[S]")) {
|
|
|
|
+// Integer curPermitsPerSecond = null;
|
|
|
|
+// try {
|
|
|
|
+// curPermitsPerSecond = Integer.parseInt(value);
|
|
|
|
+// } catch (NumberFormatException e) {
|
|
|
|
+// LOG.error("value invalid. key= " + key, e);
|
|
|
|
+// continue;
|
|
|
|
+// }
|
|
|
|
+//
|
|
|
|
+// if (curPermitsPerSecond < 0) {
|
|
|
|
+// LOG.error("value is less than 0. key= " + key);
|
|
|
|
+// continue;
|
|
|
|
+// }
|
|
|
|
+//
|
|
|
|
+// if (curPermitsPerSecond > 10000) {
|
|
|
|
+// LOG.error("value is more than 10000. key= " + key);
|
|
|
|
+// continue;
|
|
|
|
+// }
|
|
|
|
+//
|
|
|
|
+// RateLimiter curRateLimiter = RateLimiter.create(curPermitsPerSecond);
|
|
|
|
+// limiterMap.put(key, curRateLimiter);
|
|
|
|
+// permitsPerSecondMap.put(key, curPermitsPerSecond);
|
|
|
|
+// }
|
|
|
|
+// }
|
|
|
|
+//
|
|
|
|
+// new Thread(new Runnable() {
|
|
|
|
+// @Override
|
|
|
|
+// public void run() {
|
|
|
|
+//
|
|
|
|
+// while (true) {
|
|
|
|
+// // 3分钟
|
|
|
|
+// Util.sleep(180);
|
|
|
|
+//
|
|
|
|
+// loadProperties();
|
|
|
|
+//
|
|
|
|
+// Map<String, Integer> updated = Maps.newHashMap();
|
|
|
|
+//
|
|
|
|
+// for (Entry<String, Integer> entry : permitsPerSecondMap.entrySet()) {
|
|
|
|
+// String key = entry.getKey();
|
|
|
|
+// Integer value = entry.getValue();
|
|
|
|
+//
|
|
|
|
+// String curValue = (String) PROPS.get(key);
|
|
|
|
+// if (StringUtils.isBlank(curValue)) {
|
|
|
|
+// continue;
|
|
|
|
+// }
|
|
|
|
+// Integer curPermitsPerSecond = null;
|
|
|
|
+// try {
|
|
|
|
+// curPermitsPerSecond = Integer.parseInt(curValue);
|
|
|
|
+// } catch (NumberFormatException e) {
|
|
|
|
+// LOG.error("value invalid. key= " + key, e);
|
|
|
|
+// continue;
|
|
|
|
+// }
|
|
|
|
+//
|
|
|
|
+// if (curPermitsPerSecond < 0) {
|
|
|
|
+// LOG.error("value is less than 0. key= " + key);
|
|
|
|
+// continue;
|
|
|
|
+// }
|
|
|
|
+//
|
|
|
|
+// if (curPermitsPerSecond > 10000) {
|
|
|
|
+// LOG.error("value is more than 10000. key= " + key);
|
|
|
|
+// continue;
|
|
|
|
+// }
|
|
|
|
+//
|
|
|
|
+// if (!value.equals(curPermitsPerSecond)) {
|
|
|
|
+// RateLimiter curRateLimiter = limiterMap.get(key);
|
|
|
|
+// curRateLimiter.setRate(curPermitsPerSecond);
|
|
|
|
+// updated.put(key, curPermitsPerSecond);
|
|
|
|
+// }
|
|
|
|
+//
|
|
|
|
+// }
|
|
|
|
+//
|
|
|
|
+// permitsPerSecondMap.putAll(updated);
|
|
|
|
+// }
|
|
|
|
+// }
|
|
|
|
+// }).start();
|
|
|
|
+// }
|
|
|
|
+//
|
|
|
|
+// private synchronized static void loadProperties() {
|
|
|
|
+// final String propertyPath = "limited.properties";
|
|
|
|
+//
|
|
|
|
+// InputStream is = ApiFlowLimitedInterceptor.class.getClassLoader().getResourceAsStream(propertyPath);
|
|
|
|
+// if (is == null) {
|
|
|
|
+// LOG.warn("{} is not exist!", propertyPath);
|
|
|
|
+// return;
|
|
|
|
+// }
|
|
|
|
+//
|
|
|
|
+// try (InputStreamReader isr = new InputStreamReader(is, "UTF-8");
|
|
|
|
+// BufferedReader br = new BufferedReader(isr);) {
|
|
|
|
+//
|
|
|
|
+// Properties curProperties = new Properties();
|
|
|
|
+// curProperties.load(br);
|
|
|
|
+//
|
|
|
|
+// PROPS.clear();
|
|
|
|
+// if (curProperties.size() > 0) {
|
|
|
|
+// PROPS.putAll(curProperties);
|
|
|
|
+//
|
|
|
|
+// LOG.info("Load api limited props size is {}", PROPS.size());
|
|
|
|
+// }
|
|
|
|
+// } catch (Exception e) {
|
|
|
|
+// LOG.error("Load api limited config fail! " + e.getMessage(), e);
|
|
|
|
+// } finally {
|
|
|
|
+// try {
|
|
|
|
+// is.close();
|
|
|
|
+// } catch (IOException e) {
|
|
|
|
+// // ignore...
|
|
|
|
+// }
|
|
|
|
+// }
|
|
|
|
+// }
|
|
|
|
+//
|
|
|
|
+// @Override
|
|
|
|
+// public boolean preHandle(HttpServletRequest request,
|
|
|
|
+// HttpServletResponse response,
|
|
|
|
+// Object handler) throws Exception {
|
|
|
|
+// if (!enable) {
|
|
|
|
+// return true;
|
|
|
|
+// }
|
|
|
|
+//
|
|
|
|
+// boolean acquired = rateLimiter.tryAcquire();
|
|
|
|
+// if (!acquired) {
|
|
|
|
+// LOG.error("Api Limited, url = {}", request.getServletPath());
|
|
|
|
+//
|
|
|
|
+// response.setStatus(HttpStatus.SERVICE_UNAVAILABLE.value());
|
|
|
|
+// ServletUtil.returnJson(new StatusResponse("503", "api limited"), response);
|
|
|
|
+// return false;
|
|
|
|
+// }
|
|
|
|
+//
|
|
|
|
+// ApiInfo apiInfo = (ApiInfo) request.getAttribute(HttpServletRequestAttribute.$_API_INFO.name());
|
|
|
|
+// if (null == apiInfo) {
|
|
|
|
+// return true;
|
|
|
|
+// }
|
|
|
|
+//
|
|
|
|
+// ApiStatusInfo apiStatusInfo = null;
|
|
|
|
+// try {
|
|
|
|
+// apiStatusInfo = ApiStatusInfoHolder.getApiStatusInfo(apiInfo.getMapping());
|
|
|
|
+// } catch (Exception e) {
|
|
|
|
+// // ignore
|
|
|
|
+// }
|
|
|
|
+//
|
|
|
|
+// if (null == apiStatusInfo) {
|
|
|
|
+// return true;
|
|
|
|
+// }
|
|
|
|
+//
|
|
|
|
+// String rateLimiterKey = apiInfo.getMapping() + "[S]";
|
|
|
|
+// RateLimiter limiter = limiterMap.get(rateLimiterKey);
|
|
|
|
+//
|
|
|
|
+// if (null != limiter) {
|
|
|
|
+// acquired = limiter.tryAcquire();
|
|
|
|
+// if (!acquired) {
|
|
|
|
+// LOG.error("[S] Api Limited, mapping = {}", apiInfo.getMapping());
|
|
|
|
+//
|
|
|
|
+// response.setStatus(HttpStatus.SERVICE_UNAVAILABLE.value());
|
|
|
|
+// ServletUtil.returnJson(new StatusResponse("503", "api limited"), response);
|
|
|
|
+// return false;
|
|
|
|
+// }
|
|
|
|
+// }
|
|
|
|
+//
|
|
|
|
+// String expression = null;
|
|
|
|
+// String expressionKey = apiInfo.getMapping() + "[E]";
|
|
|
|
+// try {
|
|
|
|
+// expression = (String) PROPS.get(expressionKey);
|
|
|
|
+// } catch (Exception e) {
|
|
|
|
+// LOG.error("error value. key= " + expressionKey, e);
|
|
|
|
+// }
|
|
|
|
+//
|
|
|
|
+// if (StringUtils.isBlank(expression)) {
|
|
|
|
+// return true;
|
|
|
|
+// }
|
|
|
|
+// expression = expression.trim();
|
|
|
|
+//
|
|
|
|
+// if (LOG.isDebugEnabled()) {
|
|
|
|
+// LOG.debug("expression=" + expression + " ; mapping=" + apiInfo.getMapping());
|
|
|
|
+// }
|
|
|
|
+//
|
|
|
|
+// Map<String, Object> env = Maps.newHashMap();
|
|
|
|
+// env.put("mean", apiStatusInfo.getMean());
|
|
|
|
+// env.put("max", apiStatusInfo.getMax());
|
|
|
|
+// env.put("min", apiStatusInfo.getMin());
|
|
|
|
+// env.put("meanRate", apiStatusInfo.getMeanRate());
|
|
|
|
+// env.put("oneMinRate", apiStatusInfo.getOneMinuteRate());
|
|
|
|
+// env.put("errPercent", apiStatusInfo.getErrorPercent());
|
|
|
|
+// env.put("errMeanRate", apiStatusInfo.getErrorMeanRate());
|
|
|
|
+//
|
|
|
|
+// boolean limited = false;
|
|
|
|
+// try {
|
|
|
|
+// limited = (Boolean) AviatorEvaluator.execute(expression, env, true);
|
|
|
|
+// } catch (Exception e) {
|
|
|
|
+// LOG.error("Get value fail. expression= " + expression, e);
|
|
|
|
+// }
|
|
|
|
+//
|
|
|
|
+// if (limited) {
|
|
|
|
+// int random = RandomUtils.nextInt(100);
|
|
|
|
+// if (random <= allowedRate) {
|
|
|
|
+// double oneMinuteRate = apiStatusInfo.getOneMinuteRate();
|
|
|
|
+//
|
|
|
|
+// int curMinCallRate = minCallRate;
|
|
|
|
+// String minCallRateKey = apiInfo.getMapping() + "[R]";
|
|
|
|
+// try {
|
|
|
|
+// String value = (String) PROPS.get(minCallRateKey);
|
|
|
|
+// if (StringUtils.isNotBlank(value)) {
|
|
|
|
+// curMinCallRate = Integer.parseInt(value.trim());
|
|
|
|
+// }
|
|
|
|
+// } catch (Exception e) {
|
|
|
|
+// LOG.error("error value. key= " + minCallRateKey, e);
|
|
|
|
+// }
|
|
|
|
+//
|
|
|
|
+// if (LOG.isDebugEnabled()) {
|
|
|
|
+// LOG.debug("minCallRate=" + curMinCallRate + "; mapping=" + apiInfo.getMapping());
|
|
|
|
+// }
|
|
|
|
+//
|
|
|
|
+// if (oneMinuteRate < curMinCallRate) {
|
|
|
|
+// return true;
|
|
|
|
+// }
|
|
|
|
+// }
|
|
|
|
+//
|
|
|
|
+// LOG.error("[ER] Api Limited, mapping = {}", apiInfo.getMapping());
|
|
|
|
+//
|
|
|
|
+// response.setStatus(HttpStatus.SERVICE_UNAVAILABLE.value());
|
|
|
|
+// ServletUtil.returnJson(new StatusResponse("503", "api limited"), response);
|
|
|
|
+// return false;
|
|
|
|
+// }
|
|
|
|
+//
|
|
|
|
+// return true;
|
|
|
|
+// }
|
|
|
|
+//
|
|
|
|
+// @Override
|
|
|
|
+// public void afterCompletion(HttpServletRequest request, HttpServletResponse response,
|
|
|
|
+// Object handler, Exception ex) throws Exception {
|
|
|
|
+//
|
|
|
|
+// }
|
|
|
|
+//
|
|
|
|
+// }
|