Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can I read request body multiple times in Spring 'HandlerMethodArgumentResolver'?

Tags:

I'm trying to resolve some certain parameters of RequestMapping methods, to extract values from request body and validates them and inject them into certain annotated parameters.

@Override public Object resolveArgument(MethodParameter parameter, ModelAndViewContainer mavContainer,                               NativeWebRequest webRequest, WebDataBinderFactory binderFactory) throws Exception {     // 1, get corresponding input parameter from NativeWebRequest     // 2, validate     // 3, type convertion and assemble value to return     return null; } 

The biggest problem is that I find out that HttpServletRequest(get from NativeWebRequest) cannot read input stream(some parameters are in the request body) more than one time. So how can I retrieve Inputstream/Reader or the request body more than one time?

like image 654
Kim Avatar asked Jan 15 '16 04:01

Kim


People also ask

How do you read request body multiple times spring?

Spring's ContentCachingRequestWrapper This class provides a method, getContentAsByteArray() to read the body multiple times. This class has a limitation, though: We can't read the body multiple times using the getInputStream() and getReader() methods. This class caches the request body by consuming the InputStream.

How do you read a body request in spring boot?

To retrieve the body of the POST request sent to the handler, we'll use the @RequestBody annotation, and assign its value to a String. This takes the body of the request and neatly packs it into our fullName String. We've then returned this name back, with a greeting message.

Can RequestBody and RequestParam be used at the same time in Spring MVC?

The @RequestBody is processed first. Spring will consume all the HttpServletRequest InputStream . When it then tries to resolve the @RequestParam , which is by default required , there is no request parameter in the query string or what remains of the request body, ie. nothing.


1 Answers

You can add a filter, intercept the current HttpServletRequest and wrap it in a custom HttpServletRequestWrapper. In your custom HttpServletRequestWrapper, you read the request body and cache it and then implement getInputStream and getReader to read from the cached value. Since after wrapping the request, the cached value is always present, you can read the request body multiple times:

@Component public class CachingRequestBodyFilter extends GenericFilterBean {     @Override     public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain chain)             throws IOException, ServletException {         HttpServletRequest currentRequest = (HttpServletRequest) servletRequest;         MultipleReadHttpRequest wrappedRequest = new MultipleReadHttpRequest(currentRequest);         chain.doFilter(wrappedRequest, servletResponse);     } } 

After this filter, everybody will see the wrappedRequest which has the capability of being read multiple times:

public class MultipleReadHttpRequest extends HttpServletRequestWrapper {     private ByteArrayOutputStream cachedContent;      public MultipleReadHttpRequest(HttpServletRequest request) throws IOException {         // Read the request body and populate the cachedContent     }      @Override     public ServletInputStream getInputStream() throws IOException {         // Create input stream from cachedContent         // and return it     }      @Override     public BufferedReader getReader() throws IOException {         // Create a reader from cachedContent         // and return it     } } 

For implementing MultipleReadHttpRequest, you can take a look at ContentCachingRequestWrapper from spring framework which is basically does the same thing.

This approach has its own disadvantages. First of all, it's somewhat inefficient, since for every request, request body is being read at least two times. The other important drawback is if your request body contains 10 GB worth of stream, you read that 10 GB data and even worse bring that into memory for further examination.

like image 155
Ali Dehghani Avatar answered Sep 28 '22 10:09

Ali Dehghani