Issue
I want to print some text before redirecting my response to google search link..but I am unable to print it.My code for redirecting servlet is as below:
package sendredirect;
import java.io.IOException;
import java.io.PrintWriter;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
public class SendRedirectServlet extends HttpServlet {
private static final long serialVersionUID = 1L;
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
resp.setContentType("text/html");
PrintWriter out = resp.getWriter();
out.println("Hello World");
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}
String textToSearch = req.getParameter("textToGoogle");
resp.sendRedirect("https://www.google.com/search?q="+ textToSearch);
out.close();
}
}
Why I couldn't get the output from the code out.println("Hello World");
in my browser before redirecting to google search .
My index.html
file is as below:
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Send Redirect Example</title>
</head>
<body>
<form action="sr" method="GET">
<input type="text" name="textToGoogle"><br>
<input type="submit" value="Google It!">
</form>
</body>
</html>
and my web.xml
file is as below:
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd" id="WebApp_ID" version="3.0">
<display-name>ServletSendRedirect</display-name>
<welcome-file-list>
<welcome-file>index.html</welcome-file>
<welcome-file>index.htm</welcome-file>
<welcome-file>index.jsp</welcome-file>
<welcome-file>default.html</welcome-file>
<welcome-file>default.htm</welcome-file>
<welcome-file>default.jsp</welcome-file>
</welcome-file-list>
<servlet>
<servlet-name>SR</servlet-name>
<servlet-class>sendredirect.SendRedirectServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>SR</servlet-name>
<url-pattern>/sr</url-pattern>
</servlet-mapping>
</web-app>
Solution
sendRedirect
is sending a response code like 302 or 304 (I assume 302 Temporary Redirect) to the browser and a Location
header telling the client where to go instead. This is then handled transparently by the browser, without it ever having to display anything.
To see the HTTP response for yourself use curl -v http://yourendpoint
, or use Postman if you prefer a browser based tool. Or you can look at the request/response in your browser dev tools, under the network tab (you might have to find an option that doesn't clear the inpector history on page load).
Alternatively you would pass the redirect url to the page and do the redirect later with javascript.
You could respond with something like this, to display the page and redirect after 3 seconds:
<html>
<body>
Hello there, redirecting soon
<script type="application/javascript">
setTimeout(function() {
window.location.href = "https://www.google.com/search?q=dogs";
}, 3000);
</script>
</body>
</html>
Why couldn't I print, If i close the PrintWriter after redirecting it to google link?
I'll start from the other direction first, flushing/closing before calling sendRedirect
.
When you call out.println("Hello World");
, tomcat writes "Hello World" to an OutputBuffer here, it is stored in memory until it is flushed. At this point you could still change the response code using something like resp.setStatus(201);
because nothing has been sent back to the client.
As soon as you flush the Writer with out.flush()
, or out.close()
Tomcat has to pick what Headers to write to the HTTP response, as they must come before the body. Like this:
HTTP/1.1 200
Content-Type: text/html;charset=ISO-8859-1
Date: Mon, 14 Jun 2021 02:05:46 GMT
Hello World
See here, on the first flush of the output buffer. It sends headers, which then sets the response to committed.
This is when the response is committed
as in your stack trace. You cannot change the headers or status code at this point. So there is no going back and changing to a 302.
When you call sendRedirect
after the first flush then it fails with error if the response is committed for the above reason.
If you go the other way and print to the in-memory buffer, do not flush and then call sendRedirect
, one of the first things it does is reset the output buffer. Discarding your string before it proceeds to send the status code and Location header.
Answered By - roby