Is it possible to forward or redirect from a servl

2019-02-09 15:29发布

问题:

The logic is that the filter gets hit, the condition is not true, so it goes through the filter chain. After the response is committed, the filter gets hit, and the condition is now true (a request attribute was set). It goes in to execute the forward, but the page never forwards. I know this has something to do with the response being committed because I tested different logic where it forwards before it hits the chain for the first time, and it does forward successfully.

public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
            throws IOException, ServletException {

    HttpServletRequest httpServletRequest = (HttpServletRequest)request;

    if (some condition equals true) {
        httpServletRequest.getRequestDispatcher("/home.jsp").forward(request, response);
        return;
    } else {
        chain.doFilter(request, response);
    }
}

Example from my deployment descriptor:

<filter>
    <filter-name>MyFilter</filter-name>
    <filter-class>com.filters.MyFilter</filter-class>
</filter>

<filter-mapping>
    <filter-name>MyFilter</filter-name>
    <url-pattern>*.jsp</url-pattern>
    <dispatcher>REQUEST</dispatcher>  
    <dispatcher>FORWARD</dispatcher> 
</filter-mapping>

回答1:

The "committed" status of an HttpServletResponse is really a way of saying whether the response headers have been written to the underlying socket. A "committed" response has had (at least) the first line written. Since the first line of the response contains the status code, it follows that you cannot change the status code of a committed response ... and that means it is too late to change the status to 3xx to do a redirect. Similarly, you cannot do a local forward because you've already started sending the response.



回答2:

You can achieve what you want by using a custom HttpServletResponse. You pass this wrapped HttpServletResponse down the filter chain. You can provide a local OutputStream that stores all the write requests, local variables to store the status code and headers. Once you are back in your filter you can then decide to perform the redirect or copy back the results from the local variables from the wrapper into the original ServletResponse (i.e. set the status code and header and copy the results from the local output stream into the servlet response's output stream).

Edit:

Refer to the Programming Customized Requests and Responses section for a code example which uses a CharResponseWrapper. The example uses a custom Writer, but it can be easily extended to an OutputStream. Based on how your Servlet is used, you need to override one or both of getWriter() and getOutputStream() to delay committing anything onto the original response. In addition, you will need to override isCommitted() to return false, so that the forward can be executed at any time down the filter chain. You will also need to override resetBuffer() to initialize a new OutputStream/Writer to store the new content (including headers) after the redirect/forward.