0

From postman I am hitting a post request like http://localhost:8084/abc/api/v1/xyz having payload and header. we have configured a Filter class extending GenericFilterBean before it hits the Controller. Its executing all the codes of Filter class fine but while executing 'chain.doFilter(request, response);' in the end to forward request to controller method its throwing below exception.In Filter class we are reading the payload and saving in audit table. In Controller class method we have parameters like @RequestBody annotaion, @Context HttpServletRequest, BindingResult.

18:59:25,779 INFO [stdout] (default task-1) 18:59:25,778||WARN |AbstractHandlerExceptionResolver:197|Resolved [org.springframework.http.converter.HttpMessageNotReadableException: I/O error while reading input message; nested exception is java.io.IOException: UT010029: Stream is closed]

Kindly suggest on this.

Diana
  • 1,555
  • 4
  • 11
  • 17
  • Hey if you are using Spring boot, Turn on Debug logging and watch for [Source : PushBackInputStream] it will give clear information on which you are having an error – Balachandar Rangasamy Nov 15 '20 at 05:36

1 Answers1

2

Is your filter reading the contents of the request? If so then you'll need to look at alternatives to this, as the input stream is not likely to be reusable without some assistance.

Can you post some code from the filter method?


Spring provides at least one mechanism to work around this, which might be helpful here, specifically the ContentCachingRequestWrapper. You can either create a new Filter which wraps the actual request in this wrapper, or you can simply make use of it yourself in your filter.

You might update your filter with something like this

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

   // todo: your magic code, using wrappedRequest to access the body of the request

   // note: passing through the wrapped request,
   // which allows later handlers to also access the request
   chain.doFilter(wrappedRequest, servletResponse);
}

Note the documentation for ContentCachingRequestWrapper notes

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

The error that you're receiving indicates you're reading the InputStream of the request, and you should rather simply access the getContentAsByteArray method of the wrapper.

ptomli
  • 11,730
  • 4
  • 40
  • 68
  • yes its reading the headers and payload values coming with the request. – Diana Nov 13 '19 at 16:34
  • Even after using 'ContentCachingRequestWrapper', getting same error – Diana Nov 13 '19 at 17:05
  • Will we have to also use this Wrapper class in place of HttpservletRequest in our controller method? – Diana Nov 13 '19 at 19:20
  • When you read the content of the request, do you do so by accessing servletRequest or wrappedRequest? – ptomli Nov 14 '19 at 05:40
  • 1
    I've updated the answer to highlight where you're probably going wrong – ptomli Nov 14 '19 at 06:39
  • I do by accessing servletRequest not wrappedRequest. will we have to modify anything in our controller method parameters. we r using parameters like RequestBody and @Context final HttpServletRequest in our controller method – Diana Nov 14 '19 at 07:05
  • No, the controller should just be able to use the request (unless it's accessing the input stream directly). It's also possible the built-in Spring convertion/mapping may try to use the input steam directly, in which case you may have more luck using a BufferedInputStream and resetting it – ptomli Nov 14 '19 at 07:27
  • Thanks it worked. I used your code in filter class and in my controller method i just had to typecast like byte[] bb = ((ContentCachingRequestWrapper) httpServletRequest).getContentAsByteArray(); String json = new String(bb); @ptomli – Diana Nov 14 '19 at 10:34
  • Also i was able to achieve this requirement via this link. Can you suggest which one will be performance wise better. https://stackoverflow.com/questions/10457963/spring-rest-service-retrieving-json-from-request – Diana Nov 14 '19 at 10:40