The RequestDispatcher.forward() method facilitates server-side request routing to another web component. When invoked, the servlet container first clears the response output buffer associated with the originating request. If the designated target is a Servlet or JSP, the container invokes its service() method; for static assets like HTML files, the container directly reads and transmits the file contents to the client.
Key behavioral constraints include:
- The original response payload is discarded during the buffer-clearing phase. Consequently, only the dispatched resource generates the final client output.
- Attempting to forward after committing the response (via
flushBuffer(),close(), or implicit auto-flush) triggers anIllegalStateException. Developers must ensure no partial responses are flushed prior to the dispatch call. - Operation remains strictly internal to the application server. The client browser's address bar reflects the initial URL, and both
HttpServletRequestandHttpServletResponseinstances are passed intact to the destination component. - Cross-domain or external URL redirection is unsupported. Only resources within the same deployment context can be targeted.
Implementation Example
The following code demonstrates a clean separation between an initiating handler and a processing endpoint. Parameter validation and proper stream handling are included to prevent common commit exceptions.
package org.example.web.handlers;
import jakarta.servlet.RequestDispatcher;
import jakarta.servlet.ServletException;
import jakarta.servlet.annotation.WebServlet;
import jakarta.servlet.http.HttpServlet;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import java.io.IOException;
@WebServlet("/initial-endpoint")
public class InitialEndpoint extends HttpServlet {
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
String transactionAmount = request.getParameter("amount");
if (transactionAmount == null || transactionAmount.isEmpty()) {
throw new ServletException("Missing transaction amount parameter");
}
RequestDispatcher dispatcher = request.getRequestDispatcher("/final-endpoint");
dispatcher.forward(request, response);
// Execution stops here from the client perspective.
// Do not attempt to modify headers or write bodies after this line.
}
}
package org.example.web.handlers;
import jakarta.servlet.ServletException;
import jakarta.servlet.annotation.WebServlet;
import jakarta.servlet.http.HttpServlet;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import java.io.PrintWriter;
@WebServlet("/final-endpoint")
public class FinalEndpoint extends HttpServlet {
@Override
protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
String rawAmount = request.getParameter("amount");
response.setContentType("text/plain;charset=UTF-8");
PrintWriter out = response.getWriter();
out.println("Transaction Processed: $" + rawAmount + " credited successfully.");
}
}