HTTP Response Object
Overview of the Response Object
In web applications, a response represants the server's processed result of a client request, delivered back to the client. In B/S architecture, this means returnign data to the browser. The response object in JavaWeb is used to implement this functionality.
The Servlet specification defines both protocol-independent (ServletResponse) and protocol-dependent (HttpServletResponse) interfaces. This discussion focuses on HTTP-related responses using HttpServletResponse. The servlet container (like Tomcat) provides the implementation; developers do not need to create custom implementations. The container instantiates the object and passes it to servlet methods like doGet and doPost.
Common HTTP Status Codes
| Status Code | Description |
|---|---|
| 200 | Success |
| 302, 307 | Redirection (307 is newer) |
| 304 | Resource not modified (cache used) |
| 400 | Bad request (often invalid parameters) |
| 404 | Resource not found |
| 405 | HTTP method not allowed |
| 500 | Internal server error |
General categories:
- 1xx: Informational
- 2xx: Success
- 3xx: Redirection
- 4xx: Client error
- 5xx: Server error
Practical Examples
1. Outputting Chinese Text with Byte Stream
When outputting non-ASCII text via a byte stream, character encoding mismatches between the server and browser can cause garbled text. The server's default encoding (e.g., UTF-8) may differ from the browser's default (e.g., GBK). Solutions include setting the response header Content-Type to specify the charset.
public class ByteStreamEncodingServlet extends HttpServlet {
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
String message = "Byte stream output with Chinese characters";
// Recommended approach: Set content type and charset
resp.setContentType("text/html;charset=UTF-8");
ServletOutputStream output = resp.getOutputStream();
output.write(message.getBytes("UTF-8"));
}
}
2. Outputting Chinese Text with Character Writer
Using PrintWriter also requires setting the correct charset before obtaining the writer to prevent internal encoding issues.
public class WriterEncodingServlet extends HttpServlet {
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
String text = "Character writer output with Chinese";
// Set encoding and content type before getting writer
resp.setContentType("text/html;charset=UTF-8");
PrintWriter writer = resp.getWriter();
writer.write(text);
}
}
The method setContentType("text/html;charset=UTF-8") performs two actions: sets the response object's character set (affecting the PrintWriter) and informs the browser of the content type and charset.
3. Generating a CAPTCHA Image
Images can be generated dynamically using BufferedImage and Graphics2D, then written to the response output stream.
public class CaptchaServlet extends HttpServlet {
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
int width = 180;
int height = 40;
BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
Graphics2D graphics = image.createGraphics();
graphics.setColor(Color.LIGHT_GRAY);
graphics.fillRect(0, 0, width, height);
graphics.setColor(Color.BLUE);
graphics.drawRect(0, 0, width - 1, height - 1);
Random rand = new Random();
graphics.setColor(Color.DARK_GRAY);
for (int i = 0; i < 8; i++) {
graphics.drawLine(rand.nextInt(width), rand.nextInt(height),
rand.nextInt(width), rand.nextInt(height));
}
graphics.setFont(new Font("Arial", Font.BOLD, 28));
graphics.setColor(Color.RED);
String captcha = "";
for (int i = 0; i < 4; i++) {
captcha += rand.nextInt(10);
}
graphics.drawString(captcha, 30, 30);
graphics.dispose();
resp.setContentType("image/jpeg");
ImageIO.write(image, "jpg", resp.getOutputStream());
}
}
4. Controlling Cache with Response Headers
Static resources can be cached by clients. The Expires header defines a future time until which the resource is considered fresh.
public class CacheControlServlet extends HttpServlet {
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
// Cache for 1 hour
long expiryTime = System.currentTimeMillis() + 3600_000;
resp.setDateHeader("Expires", expiryTime);
resp.setContentType("text/html;charset=UTF-8");
resp.getWriter().write("Cached content");
}
}
5. Refreshing the Page Automatically
The Refresh header instructs the browser to reload the page or navigate to a new URL after a specified delay.
public class AutoRefreshServlet extends HttpServlet {
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
resp.setContentType("text/html;charset=UTF-8");
PrintWriter out = resp.getWriter();
out.write("Redirecting in 3 seconds...");
// Refresh after 3 seconds to a login page
resp.setHeader("Refresh", "3;URL=/login.html");
}
}
6. Request Redirection
Redirection is a client-side action where the browser makes a new request to a different URL. The address bar changes.
public class RedirectionServlet extends HttpServlet {
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
// Redirect to another servlet
resp.sendRedirect("DestinationServlet");
// Internally, this sets status 302 and Location header
}
}
7. File Download
To force a file download, set the Content-Type to application/octet-stream and the Content-Disposition header to attachment.
public class FileDownloadServlet extends HttpServlet {
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
String filePath = getServletContext().getRealPath("/uploads/image.png");
File file = new File(filePath);
resp.setHeader("Content-Type", "application/octet-stream");
resp.setHeader("Content-Disposition", "attachment;filename=" + file.getName());
try (InputStream in = new FileInputStream(file);
OutputStream out = resp.getOutputStream()) {
byte[] buffer = new byte[4096];
int bytesRead;
while ((bytesRead = in.read(buffer)) != -1) {
out.write(buffer, 0, bytesRead);
}
}
}
}
8. Important Notes on Response Objects
- The byte stream (
getOutputStream()) and character writer (getWriter()) are mutually exclusive; only one can be used per response. - Streams obtained from the response object do not need to be closed manually; the container handles cleanup.
public class ResponseNotesServlet extends HttpServlet {
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
// Using OutputStream
ServletOutputStream outStream = resp.getOutputStream();
outStream.write("Data".getBytes());
// Attempting to also use Writer here would cause an IllegalStateException
}
}
HTTP Request Object
Overview of the Request Object
A request represents a client's inquiry to the server for resources. In JavaEE, ServletRequest and HttpServletRequest objects encapsulate this, with the latter being HTTP-specific.
Common Methods and Examples
1. Retrieving Path and Address Information
public class RequestInfoServlet extends HttpServlet {
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
System.out.println("Server IP: " + req.getLocalAddr());
System.out.println("Server Port: " + req.getLocalPort());
System.out.println("Client IP: " + req.getRemoteAddr());
System.out.println("Request URI: " + req.getRequestURI());
System.out.println("Request URL: " + req.getRequestURL());
System.out.println("Query String: " + req.getQueryString());
System.out.println("Servlet Path: " + req.getServletPath());
}
}
2. Reading Request Headers
public class HeaderReaderServlet extends HttpServlet {
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
// Get a single header value
String encoding = req.getHeader("Accept-Encoding");
// Get all values for a header (if multiple)
Enumeration<String> acceptValues = req.getHeaders("Accept");
// Iterate through all header names
Enumeration<String> headerNames = req.getHeaderNames();
while (headerNames.hasMoreElements()) {
String name = headerNames.nextElement();
System.out.println(name + ": " + req.getHeader(name));
}
}
}
3. Obtaining Request Parameters
Form data can be retrieved via getParameter, getParameterValues, getParameterNames, and getParameterMap.
public class ParameterProcessingServlet extends HttpServlet {
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
// Single value parameter
String username = req.getParameter("username");
// Multiple values for same parameter name (e.g., checkboxes)
String[] hobbies = req.getParameterValues("hobby");
// All parameter names
Enumeration<String> paramNames = req.getParameterNames();
// Direct map of parameters
Map<String, String[]> paramMap = req.getParameterMap();
}
}
4. Populating a JavaBean with Request Parameters
Using Apache Commons BeanUtils simplifies mapping parameters to object properties, assuming form field names match bean property names.
import org.apache.commons.beanutils.BeanUtils;
public class BeanPopulationServlet extends HttpServlet {
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
User user = new User();
try {
BeanUtils.populate(user, req.getParameterMap());
} catch (Exception e) {
e.printStackTrace();
}
System.out.println(user);
}
}
5. Reading Request Body as a Stream
For non-form data (e.g., raw POST data), the input stream can be read directly.
public class StreamReaderServlet extends HttpServlet {
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
ServletInputStream input = req.getInputStream();
byte[] buffer = new byte[1024];
int length;
while ((length = input.read(buffer)) != -1) {
System.out.write(buffer, 0, length);
}
}
}
6. Handling Chinese Character Encoding in Requests
- POST requests: Use
request.setCharacterEncoding("UTF-8")before accessing parameters. - GET requests: In Tomcat 8.5+, URI encoding is handled automatically. For older versions, manual decoding might be required.
public class EncodingServlet extends HttpServlet {
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
req.setCharacterEncoding("UTF-8");
String name = req.getParameter("name");
// Process name...
}
}
7. Request Forwarding
Forwarding is a server-side mechanism to pass a request to another resource within the same context. The browser's address bar does not change, and request attributes are preserved.
public class ForwardingServlet extends HttpServlet {
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
req.setAttribute("dataKey", "sampleValue");
RequestDispatcher dispatcher = req.getRequestDispatcher("/DestinationServlet");
dispatcher.forward(req, resp);
}
}
8. Request Inclusion
Inclusion merges the output of multiple servlets into a single response. The included servlet's response headers are typically ignored.
public class IncludingServlet extends HttpServlet {
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
resp.getWriter().write("Content from main servlet. ");
RequestDispatcher dispatcher = req.getRequestDispatcher("/IncludedServlet");
dispatcher.include(req, resp);
}
}
Key Points
- Forwarding vs. Redirection: Forwarding (
forward) is server-side, one request, address unchanged. Redirection (sendRedirect) is client-side, two requests, address changes. - Request Scope: Attributes set via
setAttributeare available during the current request chain (forward/includes). - Inclusion Headers: Response headers from an included servlet are generally lost; only the including servlet's headers are sent.