Get RequestBody and ResponseBody at HandlerInterceptor
As far as I know, RequestBody
and ResponseBody
can be read only once. So you should not read them in an Interceptor
.
Here's some explanation.
How can I get a body data from the request in an ExceptionHandler in Spring Boot?
The comments regarding using the ContentCachingRequestWrapper
are accurate, this is the implementation using your controller advice that should work.
@Component
public class MyFilter implements Filter {
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain)
throws IOException, ServletException {
ContentCachingRequestWrapper contentCachingRequestWrapper = new ContentCachingRequestWrapper(
(HttpServletRequest) servletRequest);
filterChain.doFilter(contentCachingRequestWrapper, servletResponse);
}
}
The advice
@RestControllerAdvice
public class CustomExceptionHandler extends ResponseEntityExceptionHandler {
@Override
protected ResponseEntity<Object> handleMethodArgumentNotValid(MethodArgumentNotValidException ex, HttpHeaders headers,
HttpStatus status, WebRequest request) {
ContentCachingRequestWrapper nativeRequest = (ContentCachingRequestWrapper) ((ServletWebRequest) request).getNativeRequest();
String requestEntityAsString = new String(nativeRequest.getContentAsByteArray());
log.debug(requestEntityAsString);
return super.handleMethodArgumentNotValid(ex, headers, status, request);
}
}
How to modify request body before reaching controller in spring boot
Short Answer
Yes, but not easily.
Details
I know of three options to change the body of a request
"before" it arrives at the handler method in the controller;
- Use AOP to change the request before the method is called.
- Create an HTTP filter.
- Create a custom Spring HandlerInterceptor.
Since you are already using spring-boot,
option 3, custom Spring HandlerInterceptor,
seems like the best option for you.
Here is a link to a Baeldung Article covering spring HandlerInterceptors.
The Baeldung article is not the full answer for your problem
because you can only read the InputStrem
returned by HttpServletRequest
one time.
You will need to create a wrapper class that extends HttpServletRequest
and wrap every request in your wrapper class within your custom HandlerInterceptor or in a custom Filter (Filter might be the way to go here).
Wrapper Class
- Read the
HttpServletRequest
InputStream in the wrapper class constructor - Modify the body per your requirements.
- Write the modified body to a
ByteArrayOutputStream
. - Use
toByteArray
to retrieve the actualbyte[]
from the stream. - Close the ByteArrayOutputStream (try-with-resources is good for this).
- Override the
getInputStream
method. - Wrap the
byte[]
in a ByteArrayInputStream every time thegetInputStream
is called. Return this stream.
How To Wrap the Request
- In your Filter, instantiate your wrapper class and pass in the original request (which is a parameter to the doFilter method).
- Pass the wrapper to the chain.doFilter method (not the original request).
Related Topics
How to Handle JPA Unique Constraint Violations
Arraylist - How to Check If an Index Exists
Is There an Invisible Character That Is Not Regarded as Whitespace
Intellij Incorrectly Saying No Beans of Type Found for Autowired Repository
403 Forbidden When I Try to Post to My Spring API
How to Check If an Int Is a Null
How to Know If All the Variables in a Class Are Null
How to Prevent Duplicate Results in Hibernate
How to Use Variables in One Method into Another Method
Java 8 Lambda Create List of Strings from List of Objects
How to Upload a File and Json Data in Postman
How Many Times Will This Loop Execute
How to Pass JavaScript Values to Scriptlet in Jsp
How to Get the Part After the Decimal Point in Java
Remove Duplicates from a List of Objects Based on Property in Java 8
How to Update Each Element in a List in Java 8 Using Stream API
How to Determine If a List of String Contains Null or Empty Elements