SpringBoot выполняет перехватчик несколько раз в одном запросе. В чем причина этого?

#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  

После многих попыток я нашел:

  1. Параметр originalUrl не передается в запросе, и перехватчик может работать нормально. Будь то spring.profiles.active=разработчик или spring.profiles.active=тест.
  2. spring.profiles.active=тест, и исходный параметр URL включен в запрос, перехватчик будет выполняться несколько раз, что приведет к неправильному управлению частотой.
  3. 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 действия по обеспечению безопасности и ограничению скорости. Но это что-то другое.