Spring AOP вокруг контроллеров не работает при неправильном вводе запроса - PullRequest
0 голосов
/ 20 января 2020

Я написал регистратор запросов / ответов, используя @Around:

@Around(value = "execution(* com.xyz.example.controller.*.*(..))")
public Object logControllers(ProceedingJoinPoint joinPoint) throws Throwable {
    Object response = joinPoint.proceed();

    // Log request and response

    return response;
}

Однако я понял, что введенные данные запроса (ie. Тело запроса) недействительны, например, если number является обязательным полем в теле запроса, и оно должно быть Integer, но я ввел String в качестве его значения и отправил в конечную точку, Spring вернет ответ 400, не затрагивая этот аспект. Но если я ввел некоторый ввод git, пусть запрос фактически проходит через конечную точку, то этот аспект выполнит свою работу. Так есть ли способ, чтобы этот аспект работал в ситуации, которую я упомянул выше?

PS: я пытался использовать @ControllerAdvice с @ExceptionHandler, но похоже, что он также не будет go из-за вышеупомянутого аспект логгера, если @ControllerAdvice запущен.

1 Ответ

2 голосов
/ 20 января 2020

Прежде всего, позвольте мне объяснить, почему ваши попытки с аспектом и советом контроллера не увенчались успехом.

Поток идет следующим образом (значительно упрощенный, но все же, надеюсь, «глубокий», чтобы объяснить суть):

  1. Запрос попадает в Интернет (например, tomcat)
  2. Tomcat преобразует необработанный текст HTTP-запроса (полезную нагрузку) в java классы, представляющие запрос http (HttpServletRequest et c )
  3. Если указано, запрос проходит через javax.servlet.Filter-s, которые работают с «необработанными» объектами запроса.
  4. Tomcat находит сервлет для обработки запроса. В этом случае его Spring MVC's DispatcherServlet
  5. Tomcat передает выполнение DispatcherServlet. В этот момент приходит пружина.
  6. DispatcherServlet находит, что контроллер вызывается
  7. DispatcherServlet «понимает», как преобразовать данные из необработанного запроса в параметры метода, указанного в контроллере ( что должно быть сопоставлено с «путем», как преобразовать тело и т. д.). Например, если ожидается, что он будет JSON, Джексон будет использоваться для фактического преобразования.
  8. Контроллер вызывается

Теперь, обновляя часть AOP: рекомендация AOP охватывает ваш контроллер эффективно предоставляя прокси "неотличимый" от реального контроллера. Таким образом, этот прокси может быть вызван (прозрачно для Spring MVC) во время шага "8"

. Это «счастливый путь». Однако что произойдет, если запрос будет неправильным?

  • Если это не Http-запрос, он не выполнится на шаге 2 и явно не достигнет шага 8
  • Если он действителен HTTP-запрос, но не отображается правильно (например, неправильный путь отображения URL-адреса и т. д. c). DispatcherServlet не найдет соответствующий контроллер для его обработки, поэтому он не выполнится во время шага "6"
  • Если JSON полезная нагрузка неверна, шаг 7 завершится неудачей.

В любом случае он не достигнет шага 8, и именно поэтому ваш совет не вызывается

Теперь о @ControllerAdvice. Это «специальный» механизм обработки исключений весной MVC, который помогает правильно отображать исключения, возникающие внутри контроллера (или класс, к которому обращается контроллер, например, service, Dao, et c.). Поскольку поток даже не достиг контроллера, здесь он в значительной степени не имеет значения.

Теперь с точки зрения или разрешения:

Есть две основные абстракции, которые вы можете попробовать сделать программно:

  • Фильтр javax.servlet , чтобы сделать это в виде веб-контейнера
  • HandlerInterceptorAdapter , чтобы сделать это в пружине MVC way

В обоих случаях вам придется иметь дело с необработанным запросом. Вот пример пружинного mvc способа:

@Component
public class LoggingInterceptor 
  extends HandlerInterceptorAdapter {

    @Override
    public boolean preHandle(
      HttpServletRequest request, 
      HttpServletResponse response, 
      Object handler) {
        return true; // called before the actual controller is invoked
    }

    @Override
    public void afterCompletion(
      HttpServletRequest request, 
      HttpServletResponse response, 
      Object handler, 
      Exception ex) {
        // called after the controller has processed the request,
        // so you might log the request here
    }
}

Чтобы правильно зарегистрировать и отобразить перехватчик, используйте WebMvcConfigurer. В целом см. этот пример

Другие решения включают в себя:

  1. Spring Boot Actuator имеет конечную точку, которая регистрирует 50 последних запросов
  2. Tomcat (если вы используете tomcat, например) имеет специальный Valve, который может регистрировать запросы (доступ к стилю журнала). Смотрите эту тему , например
...