最近在整理Web开发学习笔记时,发现很多新手对请求转发(Request Forwarding)和响应重定义(Response Redirection)这两个基础但重要的概念容易混淆。作为过来人,我决定把当初踩坑的经验系统梳理出来,用最直白的语言讲清楚它们的区别、应用场景和实际代码实现。
请求转发就像把工作转交给同事处理:浏览器发起请求到Servlet A后,A在服务器内部把请求连同所有参数原封不动转给Servlet B处理,整个过程对浏览器完全透明。关键特点:
典型代码实现:
java复制request.getRequestDispatcher("/targetServlet").forward(request, response);
响应重定义则是告诉浏览器:"你要的资源在别处,重新去那个地址请求"。整个过程分为两步:
关键特征:
基础实现代码:
java复制response.sendRedirect("http://newlocation.com/target");
java复制// 登录Servlet片段
if(authenticate(username, password)) {
// 转发到欢迎页(保持登录状态)
request.setAttribute("user", userObj);
request.getRequestDispatcher("/welcome.jsp").forward(request, response);
} else {
// 重定向回登录页(清除错误表单)
response.sendRedirect(request.getContextPath() + "/login.jsp?error=1");
}
java复制// 添加商品到购物车后
if(isMobileDevice(request)) {
// 移动端使用重定向避免重复提交
response.sendRedirect("/mobile/cart.jsp");
} else {
// PC端直接转发显示最新购物车
request.getRequestDispatcher("/cart.jsp").forward(request, response);
}
重要提示:始终验证目标路径,避免../等目录遍历攻击
防护方案:
java复制// 安全的相对路径重定向
String safePath = "/app" + sanitize(inputPath);
response.sendRedirect(request.getContextPath() + safePath);
错误现象:
code复制java.lang.IllegalStateException: Cannot forward after response has been committed
解决方案:
典型错误:
java复制// 缺少contextPath导致404
response.sendRedirect("pages/profile.jsp"); // 错误
response.sendRedirect(request.getContextPath() + "/pages/profile.jsp"); // 正确
调试技巧:
通过配置实现灵活路由:
java复制String target = decideTargetByRequest(request);
request.getRequestDispatcher(target).forward(request, response);
保持数据跨重定向的方法:
java复制// 使用session临时存储
request.getSession().setAttribute("tempData", value);
response.sendRedirect("/nextStep");
// 下次请求中取出后立即清除
结合两种方式的支付流程:
java复制@Test
public void testForward() throws Exception {
TestRequest request = new TestRequest("/source");
TestResponse response = new TestResponse();
new SourceServlet().doGet(request, response);
assertEquals("/target", request.getForwardedUrl());
assertNull(response.getRedirectedUrl());
}
经过多个项目实践,我的经验是:
最后分享一个实用技巧:在开发阶段,可以添加日志记录转发/重定向的目标路径,这对调试复杂流程非常有帮助:
java复制logger.debug("Forwarding to: {}", targetPath);
// 或
logger.debug("Redirecting to: {}", redirectUrl);