3

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)?

0

1 Answer 1

1

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.

Sign up to request clarification or add additional context in comments.

5 Comments

The redirect works fine. The problem is that I need the original URI from the request. In case there is no RequestMapping for the original URI, Spring will automatically redirect(?) to the default error controller. This redirection also changes the URI in the HttpServletRequest to /error (or some such). As a result, I can no longer access the original URI (to determine where I need to redirect to). My current workaround is to have a simple controller with a RequestMapping(path = "**"), but that seems like a dirty hack.
Ah, sorry, from your description I understood that the redirection to /error is happening in spite of the interceptor's redirect. I'll update my answer then, I think you should be okay with having a Filter that just saves the original request URI as a request attribute.
There, hope that helps. Your way of using a controller definitely requires less work and if I may be frank, probably is less of a hack :) Also, if you're just doing redirection, you're probably better off with a Filter implementation instead of using an interceptor/controller approach.
It did help. Thanks a bunch for the effort :)
Don't mention it, I learned a few things along the way, too :)

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.