问题
I'm working on servlet page that renders content based on geo-location
, and I want to use both sendRedirect
and forward
together; e.g; you browse example.com/aPage.jsp
from France
; first I want the servlet to redirect you to example.com/fr/aPage.jsp
and then forward you to the resources
page.
This is what I have in my servlet:
public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
....
response.sendRedirect(REDIRECT_URL_BASED_ON_GEO);
// after redirect forward the resources page
RequestDispatcher view = request.getRequestDispatcher(RESOURCES_PAGE);
view.forward(request, response);
...
}
But I get:
java.lang.IllegalStateException: Cannot forward after response has been committed
I know the error appears because I can't use both sendRedirect
and forward
one after another, but I don't know how to achieve what I want (as described above) without this.
any help?
回答1:
response.sendRedirect(REDIRECT_URL_BASED_ON_GEO);
// after redirect forward the resources page
After that line , Your response start writing to clinet.
And you are trying to add additional data to it.
The server has already finished writing the response header and is writing the body of the content, and which point you are trying to write more to the header - of course it cant rewind.
So,Thumb rule while dealing with servlet is
Finish your logic before redirect
or forward
add return statement.So execution ends there .
回答2:
When you call
response.sendRedirect(REDIRECT_URL_BASED_ON_GEO);
you are sending your client a 302 HTTP status code with the location to redirect to. Your client then needs to make a new HTTP request to that location. Whichever Servlet is supposed to handle the path REDIRECT_URL_BASED_ON_GEO
should then use the RequestDispatcher
to forward to the resource described by RESOURCES_PAGE
.
To better explain your exception
java.lang.IllegalStateException: Cannot forward after response has been committed
a committed response is a response where HTTP headers are already sent. If we look at your code
response.sendRedirect(REDIRECT_URL_BASED_ON_GEO);
After this line, you've already sent the response along with the headers (302).
RequestDispatcher view = request.getRequestDispatcher(RESOURCES_PAGE);
view.forward(request, response);
After these lines, you're asking the resource RESOURCES_PAGE
to finish processing the request. That includes writing HTTP headers and body. But the request has already been processed and a response has already been sent, so it will fail, throwing the exception.
回答3:
You have to be aware that a redirect is a complete response to the browser and the browser will in turn issue a new request to the url you redirected to. Even though you can't really sse it when dealing with the browser you always have to be aware that this is what happens.
Now, if you use the same controller for the second request you have to check wether a redirect is necessary or you can now do the forward instead.
if (!path.startsWith(locationPrefix)) {
response.sendRedirect(locationPrefix + path);
return;
} else {
RequestDispatcher view = request.getRequestDispatcher(RESOURCES_PAGE);
view.forward(request, response);
return;
}
Of course it would be nicer to have a distinct controller per request, but depending of url structure and framework this is not always possible.
回答4:
Once you redirect, the servlet you're working on is no longer in control. You need to get the servlet that is the target of the redirect to recognize the correct condition to forward and then call forward there, with similar code:
RequestDispatcher view = request.getRequestDispatcher(RESOURCES_PAGE);
view.forward(request, response);
Even if it's the same servlet, it's a new invocation of the servlet's doGet(
or other similar method.
来源:https://stackoverflow.com/questions/18211497/servlet-cannot-forward-after-response-has-been-committed