Spring MVC получает текст сообщения перед контроллерами

#java #spring #rest #spring-mvc #post

#java — язык #spring #отдых #весна-mvc #Публикация #java #остальное #spring-mvc

Вопрос:

Мне нужно прочитать тело POST-запросов, не используя его.

Я пробовал это несколькими способами в моем пользовательском HandlerInterceptor и ничего не работает. Все, что я пытался сделать для переноса и кэширования тел запросов, в какой-то момент не сработало, возможно, даже потому, что я не могу контролировать, что делает Spring.

Итак, я подумал о другой вещи: в какой-то момент Spring попытается сопоставить тело запроса с объектом и передать его нужному контроллеру. Я могу перехватить это действие и получить этот объект до вызова контроллера?

Комментарии:

1. Почему вам нужно прочитать текст перед обработкой запроса? Что вам нужно с этим делать? Вы можете обработать запрос только один раз, и, следовательно, он не будет работать без дублирования чтения (как, например, в фильтрах ведения журнала Spring).

2. Потому что я предпочитаю регистрировать каждый запрос в одной точке, а не вставлять журнал в каждый метод в каждом контроллере.

3. Поскольку в Spring уже есть специальные фильтры, используйте их вместо того, чтобы создавать свои собственные. Для этого существуют и другие существующие решения. Все сводится к сохранению ответа в памяти и реализации чтения в оболочке запроса.

4. Вы включили ведение журнала отладки для фильтра? Иначе он ничего не будет регистрировать.

5. Он будет регистрировать только полезную нагрузку, которая обрабатывается. К вашему сведению, вы не привязываете / обрабатываете полезную нагрузку, которая не будет регистрироваться.

Ответ №1:

Как только тело запроса считывается из запроса до достижения контроллера, вы не можете нигде использовать. Итак, что вы можете сделать, это прочитать текст из HttpServletRequest в Filter реализации и установить его в ThreadLocal переменной. Затем вы можете прочитать из этого ThreadLocal . Ниже приведен пример кода.

Внутри Filter класса реализации

 try {
    YourModel yourModel = // Read the request body

    RequestContextHolder.setContext(yourModel);
}finally {
    RequestContextHolder.clearContext();
}
  

и в любой момент времени в текущем запросе вы можете сделать, как показано ниже.

 RequestContextHolder.getContext();
  

Вот RequestContextHolder класс

 public class RequestContextHolder {

    private static final ThreadLocal<YourModel> THREAD_LOCAL = new ThreadLocal<>();

    public static void setContext(YourModel yourModel) {
        THREAD_LOCAL.set(yourModel);
    }

    public static YourModel getContext() {
       return THREAD_LOCAL.get();
    }

    public static void clearContext() {
       THREAD_LOCAL.remove();
    }
}
  

Комментарии:

1. Я не понимаю: где, в моем фильтре, я могу получить тело запроса?

2. из HttpServletRequest вы можете проанализировать тело для вашего класса модели. В любом случае, вы получили решение.

3. Хорошо, но в каком методе фильтрации? И если я проанализирую текст запроса, я его использую.

4. внутри doFilter() метода и, конечно, да, вы будете его использовать. Но это задано в ThreadLocal так, что оно доступно из любого места текущего запроса.

5. Таким образом, Spring не может прочитать тело запроса, поэтому каждый запрос завершается ошибкой.

Ответ №2:

Я нашел решение: используя CommonsRequestLoggingFilter, Spring может регистрировать даже полезную нагрузку запросов. Единственная проблема, которую я нахожу, заключается в том, что я могу прочитать полезную нагрузку только в методе afterRequest, потому что в beforeRequest отсутствует.

Больше информации о CommonsRequestLoggingFilter здесь.