2

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?

tokhi
  • 21,044
  • 23
  • 95
  • 105

4 Answers4

4
 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 .

Suresh Atta
  • 120,458
  • 37
  • 198
  • 307
3

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.

Sotirios Delimanolis
  • 274,122
  • 60
  • 696
  • 724
  • In my first paragraph, let the servlet handling the redirect (therefore mapped to `REDIRECT_URL_BASED_ON_GEO`) forward to your resource. – Sotirios Delimanolis Aug 13 '13 at 14:24
  • You mean I should use two different servlets, one for `REDIRECT_URL_BASED_ON_GEO` and one for forwarding? – tokhi Aug 13 '13 at 15:23
  • Servlets are mapped to URLs. Your first servlet should handle the url `example.com/aPage.jsp`, determine you are in France, and redirect to a different url `example.com/fr/aPage.jsp`. A different Servlet can then handle that url and forward to the `resources page` resource. – Sotirios Delimanolis Aug 13 '13 at 15:27
1

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.

Bernd Ebertz
  • 1,317
  • 8
  • 10
0

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.

nanofarad
  • 40,330
  • 4
  • 86
  • 117