Marceau
Marceau

Reputation: 1703

HttpServletResponse contained in servlet filter does not perform redirect

I am using Spring 4.0.6 in a servlet application. I have an abstract base controller with some general methods for all my controllers to use.

One of these methods is a redirect. I want to have a method with signature

redirect(String path)

To send a redirect, I am using

response.sendRedirect(response.encodeRedirectURL(path));

As I would like to keep method signatures short and clean, I need to get access to the response object inside the superclass method.

In order to do this, I've followed a suggestion found online, and defined a servlet filter with a ThreadLocal HttpServletResponse.

public class ResponseFilter extends OncePerRequestFilter {

    private static final ThreadLocal<HttpServletResponse> responses = new ThreadLocal<HttpServletResponse>();

    public static HttpServletResponse getResponse() {
        return responses.get();
    }

    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
        try {
            responses.set(response);
        } finally {
            try {
                filterChain.doFilter(request, response);
            } finally {
                responses.remove();
            }
        }
    }
}

As I am using Spring security with a Java configuration, I'm adding this filter in my WebSecurityConfigurerAdapter subclass:

.addFilterAfter(rf, SwitchUserFilter.class)

Note that I have also tried adding the filter as first in the filterchain, and that I have tried using an Interceptor instead. All with the same results.

I have compared hashcodes on the response objects, and near as I can tell, the hashcodes match, but the redirect seems to be ignored. I have also looked at object ids on breakpoints in Eclipse, and there again, I have a match. The symptom is that the spring DispatcherServlet enters processDispatchResult and seems to think it needs to resolve a view. That view does not exist, as I expect to do a redirect:

javax.servlet.ServletException: File &quot;/WEB-INF/views/application/redirecttest.jsp&quot; not found

I have noticed that, if I add the response object back in my requestmapping controller method signature, the superclass redirect seems to work (even though I do not use the controller method response object at all).

Unfortunately, this behavior is reproducible both on a Mac and on Linux. I use Tomcat 7 as container.

Upvotes: 1

Views: 1333

Answers (1)

marthursson
marthursson

Reputation: 3300

Your filter should work just fine, but the problem you're facing is another. If you are using views (as you appear to do in the example) you need to return a redirect view from your controller in order to force a redirect; just instructing the response object to redirect won't work because Spring MVC infrastructure will try to do its thing (i.e. view resolution) before the Response is returned to the Servlet container.

For instance, if you use the convention to return the view name as a String from your controller method, you need to do the following in your controller:

@RequestMapping("/redirectTest")
public String redirectTest() {
  return "redirect:http://www.example.com";
}

Upvotes: 1

Related Questions