irundaia irundaia - 9 months ago 94
Java Question

Spring boot HandlerInterceptor loadbalancing

I'm implementing a (sort of) load balancing

using Spring Boot.

public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
String uri = request.getRequestURI();
if (shouldUseServer1(uri)) {
} else {

The idea is, that based on the url, we either redirect to one service or another. The application doesn't have any explicit
s (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
is replaced by
(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)?



Because of the way Spring MVC handles requests with no mapping, you'll either need a filter:

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

  public void destroy() {}

  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:

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.