4

I need to read the request payload in one of my GenericFilterBean. Beacuse I cannot call getreader twice I used ContentCachingRequestWrapper like-

HttpServletRequest httpRequest = (HttpServletRequest) request;
ContentCachingRequestWrapper cachedRequest = new ContentCachingRequestWrapper(httpRequest);

Getting the request body-

String payload = cachedRequest.getReader().lines().collect(Collectors.joining());

And chaining the request-

chain.doFilter(cachedRequest, response);

But still my controller throws-

 .w.s.m.s.DefaultHandlerExceptionResolver : Resolved exception caused by handler execution: org.springframework.http.converter.HttpMessageNotReadableException: Required request body is missing: public org.springframework.http.ResponseEntity<?> com.siemens.plm.it.sf.api.controllers.OrderController.createCCOrder(com.siemens.plm.it.de.ms.provisioning.model.sap.SapQuoteCreationArgument,javax.servlet.http.HttpServletRequest) throws java.lang.Exception

Ant ideas on how to chain the request so I can read the payload in the controller as well?

Thank you.

Itsik Mauyhas
  • 3,824
  • 14
  • 69
  • 114
  • With `ContentCachingRequestWrapper` you cannot read the body multiple times. In this tutorial there is an alternative, hope it helps. https://www.baeldung.com/spring-reading-httpservletrequest-multiple-times – Marc Sep 08 '20 at 10:40

2 Answers2

6

I faced same issue. You need to call getInputStream on requestWrapper in order to let it be cached. This is how your filter should look like:

@Component
public class CachingRequestBodyFilter extends GenericFilterBean {

    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain chain)
            throws IOException, ServletException {
        ContentCachingRequestWrapper wrappedRequest = new ContentCachingRequestWrapper((HttpServletRequest) servletRequest);

        //this line is necessary to cache InputStream
        wrappedRequest.getInputStream();
        //String requestBody = IOUtils.toString(wrappedRequest.getInputStream(), StandardCharsets.UTF_8); with this line you can map requestBody to String


        chain.doFilter(wrappedRequest, servletResponse);
    }
}

Controller:

@PostMapping(ENDPOINT)
    void endpoint(HttpServletRequest request) {
        ContentCachingRequestWrapper requestWrapper = (ContentCachingRequestWrapper) request;
        String requestBody = new String(requestWrapper.getContentAsByteArray());
        //process requestBody
}
Krzysztof K
  • 736
  • 4
  • 19
0

I think by doing this :

String payload = cachedRequest.getReader().lines().collect(Collectors.joining());

you are doing it wrong.

Try this :

String input = ByteSource.wrap(cachedRequest.getContentAsByteArray())
    .asCharSource(StandardCharsets.UTF_8).read();

As the documentation suggests:

caches all content read from the input stream and reader, and allows this content to be retrieved via a byte array

Some helpful links: Link 1, Link 2.