Как я могу прочитать тело запроса после кэширования объекта HttpServletRequest с помощью ContentCachingRequestWrapper?

Я регистрирую тело запроса, если возникает какое-то пользовательское исключение. Для этого я добавил фильтр, который кэширует объект HttpServletRequest с помощью ContentCachingRequestWrapper. Вот пример кода для этого:

@Component
public class RequestWrapperFilter extends OncePerRequestFilter {

  @Override
  protected void doFilterInternal(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, FilterChain filterChain) throws ServletException, IOException {
    filterChain.doFilter(new ContentCachingRequestWrapper(httpServletRequest), httpServletResponse);
  }

}

And, my controller class looks something like this:
@PostMapping(Paths.INSPECTION_IMAGE_SUBMIT_REQUEST_V1)
  public ResponseEntity<ResponseObject> processThisRequest(
    @RequestBody RequestObject requestObject //how am I able to access this requestObject?
  ) throws Exception {
    return someService.process(requestBody);
  }

Итак, как я могу использовать это requestObject? Так как в классе фильтра я закэшировал это, значит, метод getReader() уже должен был быть вызван для этого, верно? Значит, я не смогу прочитать requestObject, верно?

Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
В компьютерном программировании биты играют важнейшую роль в представлении и манипулировании данными на двоичном уровне. Побитовые операции...
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Приходилось ли вам сталкиваться с требованиями, в которых вас могли попросить поднять тревогу или выдать ошибку, когда метод Java занимает больше...
Полный курс Java для разработчиков веб-сайтов и приложений
Полный курс Java для разработчиков веб-сайтов и приложений
Получите сертификат Java Web и Application Developer, используя наш курс.
2
0
6 000
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Попробуйте это решение . Пока вы передаете объект wrapRequest (как указано в этой ссылке) вперед для цепочки фильтров, вы можете прочитать requestObject в своем контроллере.

В ссылке на решение, размещенной выше, должна возникнуть та же проблема, т. Е. Тело запроса должно быть нулевым, потому что оно уже прочитано кэшированием контекста в фильтре? Я сомневаюсь, как работает мое решение, поскольку я уже прочитал тело запроса в кэшировании контента до того, как оно достигнет моего контроллера?

Ankit Arora 21.12.2020 07:51
Ответ принят как подходящий

====== РЕДАКТИРОВАТЬ ======

Посмотрите, как работает ContentCachingRequestWrapper

Оболочка javax.servlet.http.HttpServletRequest, которая кэширует весь контент, прочитанный из входного потока и считывателя, и позволяет извлекать этот контент через массив байтов.

Кэширование не означает, что он читает входной поток и сохраняет его в памяти, но всякий раз, когда байты считываются из обернутого потока, кешировщик будет записывать те же байты в свой внутренний буфер.

Таким образом, ваш requestObject читается только один раз во всей цепочке фильтров, когда вы создаете ContentCachingRequestWrapper в своем фильтре, он еще ничего не кэширует.

Другая часть фреймворка будет считывать кешированный контент, вызывая метод ContentCachingRequestWrapper#getContentAsByteArray (не считывать из потока повторно, так как он уже прочитан). (Обратите внимание, что контент доступен только после того, как средство чтения тела закончит чтение входного потока, если вы вызовете его раньше, вы получите неполные данные)

======КОНЕЦ РЕДАКТИРОВАНИЯ======

Можно использовать RequestBodyAdviceAdapter


@ControllerAdvice
public class RequestAdvice extends RequestBodyAdviceAdapter {
    
    @Override
    @Nonnull
    public Object afterBodyRead(@Nonnull Object body, @Nonnull HttpInputMessage inputMessage,
        @Nonnull MethodParameter parameter, @Nonnull Type targetType,
        @Nonnull Class<? extends HttpMessageConverter<?>> converterType) {
        
        // Do something with the payload
        return super.afterBodyRead(body, inputMessage, parameter, targetType, converterType);
    }
}

Привет @Mạnh Quyết Nguyễn. Спасибо за ответ, но я хочу понять, как работает мой текущий код. Разве контроллер не должен генерировать исключение, поскольку я уже прочитал тело запроса в кеше содержимого?

Ankit Arora 21.12.2020 13:01

Другие вопросы по теме