#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 здесь.