Every servlet invocation receives one HttpServletRequest and one HttpServletResponse from the container. The request describes what the client sent; the response is the message your servlet is building for the client. Keeping that boundary clear prevents accidental sessions, incorrect encodings, and responses that are committed before their status or headers are ready.
After this lesson, you can distinguish parameters, attributes, headers, and body data; choose a character writer or binary stream; return a deliberate status and content type; and recognize when forwarding, redirecting, or writing a body changes the request lifecycle.
HttpServletRequest extends ServletRequest with HTTP-specific information. Query strings and form fields are exposed as parameters. Headers describe metadata such as accepted media types and authentication. Attributes are server-side values attached by a filter or servlet and exist only for the current request. The body is a byte or character stream and should be read once by the component that owns it.
Use getParameter() for query parameters and URL-encoded form fields, getHeader() for protocol metadata, and getAttribute() for values created inside the application. Treat every client-controlled value as untrusted: check null, length, expected format, and authorization before using it in a database query, file path, or rendered HTML.
| Source | Servlet API | Typical use |
|---|---|---|
| Query or form field | getParameter / getParameterValues | Search filters, form values |
| HTTP header | getHeader | Accept, Authorization, User-Agent |
| Server attribute | getAttribute / setAttribute | Filter-to-controller or forward data |
| Text body | getReader | JSON or other character data |
| Binary body | getInputStream | Uploads or binary protocols |
@WebServlet("/request-demo")
public class RequestDemoServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
// ===== Request Parameters =====
String name = req.getParameter("name"); // Single value
String[] tags = req.getParameterValues("tags"); // Multiple values (checkboxes)
java.util.Map<String, String[]> params = req.getParameterMap(); // All params
// ===== Request Headers =====
String userAgent = req.getHeader("User-Agent");
String contentType = req.getContentType();
String accept = req.getHeader("Accept");
java.util.Enumeration<String> headerNames = req.getHeaderNames();
// ===== Request Info =====
String method = req.getMethod(); // GET, POST, etc.
String uri = req.getRequestURI(); // /myapp/request-demo
String url = req.getRequestURL().toString(); // http://localhost:8080/myapp/request-demo
String contextPath = req.getContextPath(); // /myapp
String servletPath = req.getServletPath(); // /request-demo
String queryString = req.getQueryString(); // name=Alice&age=25
String remoteAddr = req.getRemoteAddr(); // Client IP
String remoteHost = req.getRemoteHost(); // Client hostname
int serverPort = req.getServerPort(); // 8080
// ===== Request Attributes (set by other servlets/filters) =====
req.setAttribute("processedBy", "RequestDemoServlet");
Object attr = req.getAttribute("processedBy");
// ===== Session =====
HttpSession session = req.getSession(); // Get or create session
HttpSession existing = req.getSession(false); // Get only if exists
// ===== Cookies =====
Cookie[] cookies = req.getCookies();
// ===== Request Body (for POST) =====
// req.getInputStream() - binary data
// req.getReader() - text data
resp.setContentType("text/html;charset=UTF-8");
PrintWriter out = resp.getWriter();
out.println("<p>Method: " + method + "</p>");
out.println("<p>URI: " + uri + "</p>");
out.println("<p>Name param: " + name + "</p>");
out.println("<p>Remote IP: " + remoteAddr + "</p>");
}
}
HttpServletResponse controls status, headers, cookies, content type, character encoding, and body output. Set status, content type, and encoding before calling getWriter() or getOutputStream(). Once the response buffer is flushed or filled, the response is committed and the container may already have sent its headers.
Choose getWriter() for character output such as HTML, JSON, or text, and getOutputStream() for bytes such as an image or generated archive. Do not use both for one response. A successful handler should select the status that describes the result instead of returning 200 for every outcome: 201 for a created resource, 204 for success without a body, 400 for invalid syntax, 404 for a missing resource, and 500 only for an unexpected server failure.
@WebServlet("/response-demo")
public class ResponseDemoServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
String format = req.getParameter("format");
if ("json".equals(format)) {
// ===== JSON Response =====
resp.setContentType("application/json;charset=UTF-8");
resp.setStatus(HttpServletResponse.SC_OK);
PrintWriter out = resp.getWriter();
out.println("{\"name\":\"Alice\",\"age\":25,\"role\":\"admin\"}");
} else if ("file".equals(format)) {
// ===== File Download =====
resp.setContentType("application/octet-stream");
resp.setHeader("Content-Disposition", "attachment; filename=\"data.txt\"");
resp.getWriter().println("File content here");
} else {
// ===== HTML Response =====
resp.setContentType("text/html;charset=UTF-8");
resp.setCharacterEncoding("UTF-8");
// Set response headers
resp.setHeader("X-Custom-Header", "MyValue");
resp.addHeader("Cache-Control", "no-cache, no-store, must-revalidate");
resp.setIntHeader("X-Request-Count", 42);
resp.setDateHeader("Expires", 0);
// Set status code
resp.setStatus(HttpServletResponse.SC_OK); // 200
PrintWriter out = resp.getWriter();
out.println("<h2>Response Demo</h2>");
out.println("<p>Content-Type: " + resp.getContentType() + "</p>");
out.println("<p>Buffer size: " + resp.getBufferSize() + "</p>");
}
}
}
A JSON request body is not a request parameter. Read it through getReader(), enforce a body-size limit at the container or application boundary, parse it with a maintained JSON library, and validate the resulting object. Hand-written substring parsing breaks on escaped characters, missing fields, and reordered properties.
Fetch resolves even when the server returns an HTTP error status, so a JSON endpoint should send both a meaningful status and a consistent error representation. Never echo raw exception messages, SQL details, access tokens, or stack traces to the client.
@WebServlet("/api/users")
public class UserApiServlet extends HttpServlet {
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
// Read JSON body from request
StringBuilder sb = new StringBuilder();
java.io.BufferedReader reader = req.getReader();
String line;
while ((line = reader.readLine()) != null) {
sb.append(line);
}
String jsonBody = sb.toString();
// jsonBody = {"name":"Alice","email":"alice@example.com"}
// Parse JSON (using a library like Gson or Jackson in real apps)
// For demo: simple string parsing
System.out.println("Received JSON: " + jsonBody);
// Send JSON response
resp.setContentType("application/json;charset=UTF-8");
resp.setStatus(HttpServletResponse.SC_CREATED); // 201
resp.getWriter().println("{\"status\":\"created\",\"message\":\"User created successfully\"}");
}
}
A RequestDispatcher forward stays inside the same application and keeps request attributes because the target continues the same request. sendRedirect() sends a redirect response to the client, which then creates a new request and sees a new URL. Direct body writing ends the handler with content produced by the current servlet.
Choose a forward when another server-side resource should finish rendering the current request. Choose a redirect after a successful state-changing form submission when a fresh GET prevents duplicate submission. Never write response content before a forward or redirect unless the API explicitly expects an included resource.
Try this next
0 of 3 completed
No. They are two views of the same request body; choose the character or binary API that matches the media type.
It returns an existing session or null without creating one, which avoids creating sessions for anonymous requests that do not need state.
It is committed after the container sends headers, commonly when the buffer fills, is flushed, or the request completes.
Explore 500+ free tutorials across 20+ languages and frameworks.