#java #spring #spring-boot #tomcat
#Ява #весна #пружинный ботинок #кот
Вопрос:
Я хочу добавить перехватчик, чтобы ограничить частоту доступа пользователя, но я обнаружил, что мой перехватчик будет вызываться несколько раз, что вызывает проблемы с регулировкой частоты.
Перехватчик регистра:
import org.jetbrains.annotations.NotNull; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Configuration; import org.springframework.core.env.Environment; import org.springframework.web.servlet.config.annotation.InterceptorRegistration; import org.springframework.web.servlet.config.annotation.InterceptorRegistry; import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; @SuppressWarnings("JavaDoc") @Configuration public class InterceptorRegistrar implements WebMvcConfigurer { private final String errorPath; @Autowired public InterceptorRegistrar( @NotNull Environment environment ) { this.errorPath = environment.getProperty("server.error.path", "/error"); } @Override public void addInterceptors(@NotNull InterceptorRegistry registry) { final String[] excludePaths = {"/ping", this.errorPath}; InterceptorRegistration registration; registration = registry.addInterceptor(new FrequencyInterceptor()); registration.addPathPatterns("/**").excludePathPatterns(excludePaths); } }
Перехватчик управления частотой:
import com.zhiweidata.rssarticlesimilarity.util.HttpUtil; import java.util.HashMap; import java.util.Map; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import lombok.extern.slf4j.Slf4j; import org.jetbrains.annotations.NotNull; import org.springframework.web.servlet.HandlerInterceptor; import static com.zhiweidata.rssarticlesimilarity.containers.NoMagicalValue.APPID_KEY; import static com.zhiweidata.rssarticlesimilarity.entity.vo.ResponseMessageVO.SERVICE_UNAVAILABLE; import static com.zhiweidata.rssarticlesimilarity.entity.vo.ResponseMessageVO.UNAUTHORIZED; import static org.apache.commons.lang3.StringUtils.isBlank; import static java.util.Objects.isNull; @Slf4j @SuppressWarnings("JavaDoc") public class FrequencyInterceptor implements HandlerInterceptor { private final Maplt;String, Longgt; frequency = new HashMaplt;gt;(); @Override public boolean preHandle(@NotNull HttpServletRequest request, @NotNull HttpServletResponse response, @NotNull Object handler) throws Exception { String appid = request.getParameter(APPID_KEY); log.info("url {}, appid {}", request.getServletPath(), appid); if (isBlank(appid)) { HttpUtil.write(response, UNAUTHORIZED); return false; } Long access = this.frequency.get(appid); long value; if (isNull(access)) { this.frequency.put(appid, System.currentTimeMillis()); log.info("ok"); return true; } else if ((value = System.currentTimeMillis() - access) lt; 100) { log.info("Last visit interval {}ms", value); HttpUtil.write(response, SERVICE_UNAVAILABLE); this.frequency.put(appid, System.currentTimeMillis()); return false; } else { this.frequency.put(appid, System.currentTimeMillis()); log.info("ok"); return true; } } }
Запрос на выполнение:
$ curl http://localhost:8080/rss-article-similarity/original-article/similar-articles?originalUrl=https://mobile.time-weekly.com/v2/articles/B3OAQBamp;appid=61aece263575d95d4dd8b888amp;seed=9WIBZPddQ8amp;sign=157525BCB4D7EC08ACAED8FA32DBB3F8 -v
журнал консоли:
2021-12-07 17:38:53.971 INFO 100928 --- [nio-8080-exec-4] c.z.r.interceptor.FrequencyInterceptor preHandle 38 : url /original-article/similar-articles, appid 61aece263575d95d4dd8b888 2021-12-07 17:38:53.973 INFO 100928 --- [nio-8080-exec-4] c.z.r.interceptor.FrequencyInterceptor preHandle 58 : ok 2021-12-07 17:38:54.001 INFO 100928 --- [nio-8080-exec-4] c.z.r.interceptor.FrequencyInterceptor preHandle 38 : url /original-article/original-article/similar-articles, appid 61aece263575d95d4dd8b888 2021-12-07 17:38:54.003 INFO 100928 --- [nio-8080-exec-4] c.z.r.interceptor.FrequencyInterceptor preHandle 52 : Last visit interval 30ms 127.0.0.1 - - [07/Dec/2021:17:38:54 0800] "GET /rss-article-similarity/original-article/similar-articles?originalUrl=https://mobile.time-weekly.com/v2/articles/B3OAQBamp;appid=61aece263575d95d4dd8b888amp;seed=9WIBZPddQ8amp;sign=157525BCB4D7EC08ACAED8FA32DBB3F8 HTTP/1.1" 503 81
После многих попыток я нашел:
- Параметр originalUrl не передается в запросе, и перехватчик может работать нормально. Будь то spring.profiles.active=разработчик или spring.profiles.active=тест.
- spring.profiles.active=тест, и исходный параметр URL включен в запрос, перехватчик будет выполняться несколько раз, что приведет к неправильному управлению частотой.
- spring.profiles.active=dev и исходный параметр URL в запросе, перехватчик выполняется нормально.
Мои несколько тестов изменяют только конфигурацию spring.profiles.active, и в других элементах конфигурации изменений нет.
Комментарии:
1. Очевидно, вы переписываете/пересылаете запрос, что приводит к новому запросу.
2. @M. Deinum Нет, перенаправление не используется в моем проекте. Единственное внутреннее перенаправление-это /ошибка, но я исключил ее при регистрации перехватчика.
3. Я уже говорил, что тот факт, что вы этого не делаете, не означает, что нет другой части приложения, которая это делает. Глядя на URL-адреса, он действительно делает это. Как только вы получите другой URL-адрес.
4. @M. Deinum Я могу быть уверен, что этот вид пересылки не исходит из кода моего проекта и не связан с SpringBoot, используемым во всем проекте, но это не фреймворк, официально разработанный SpringBoot. Почему только spring.profiles.active=тест с таким параметром, как originalUrl, будет отображаться такая пересылка?
5. Опять же, я не говорю, что это происходит из вашего кода проекта, но что-то, что находится в вашем проекте и не включено, когда
dev
активен профиль. Таким образом, включено что-то, что выполняет перезапись/пересылку. Также, почему вы реализуете это самостоятельно, а не используете что-то подобноеResillience4j
. Ваш перехватчик также выполняет 2 действия по обеспечению безопасности и ограничению скорости. Но это что-то другое.