I'm implementing a (sort of) load balancing HandlerInterceptor using Spring Boot.
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
String uri = request.getRequestURI();
if (shouldUseServer1(uri)) {
response.sendRedirect(server1Uri);
} else {
response.sendRedirect(server2Uri);
}
}
The idea is, that based on the url, we either redirect to one service or another. The application doesn't have any explicit RequestMappings (yet).
Now the problem is, when the interceptor is called, the request is redirected to the default Spring error handler. As a result the URI stored in the HttpServletRequest is replaced by /error (effectively denying the access to the original URI).
Is there any way to intercept a request before it is rerouted to the error handler (or to get the original uri)?
EDIT:
Because of the way Spring MVC handles requests with no mapping, you'll either need a filter:
@Component
public class CustomFilter implements Filter {
public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain)
throws IOException, ServletException {
HttpServletRequest request = (HttpServletRequest) req;
HttpServletResponse response = (HttpServletResponse) res;
request.getSession().setAttribute("ORIGINAL_REQUEST_URI", request.getRequestURI());
chain.doFilter(request, response);
// alternatively, ignore the last 2 lines
// and just do your redirects from here
// and don't continue the filter chain
}
@Override
public void destroy() {}
@Override
public void init(FilterConfig arg0) throws ServletException {}
}
Otherwise, if you'd rather not rely on the session, you'll need to make the DispatcherServlet throw an exception in case no handler mapping is found, and then send the redirect from a @ControllerAdvice error handler:
@ControllerAdvice
class NoHandlerFoundExceptionExceptionHandler {
@ExceptionHandler(value = NoHandlerFoundException.class)
public ModelAndView
defaultErrorHandler(HttpServletRequest req, NoHandlerFoundException e) throws Exception {
String uri = // resolve the URI
return new ModelAndView("redirect:" + uri);
}
}
To avoid duplication, you may want to have a common class that you'll call from both the interceptor and the error handler.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With