Servlet 转发与重定向:大白话对比 + 代码实战
一、先搞懂核心概念:什么是转发?什么是重定向?
请求转发(Forward)
大白话:服务器内部帮你跑腿,你只发一次请求,服务器自己偷偷在内部跳转到另一个资源,最后把结果给你。全程你不动,地址栏也不变。
技术特点:一次请求,一次响应,地址栏不变,可以共享 request 数据(通过 setAttribute / getAttribute)。
使用场景:内部跳转、权限校验、数据传递。
重定向(Redirect)
大白话:服务器告诉你“你去另一个地方找”,你自己(浏览器)再主动发起第二次请求。地址栏会变成新地址。
技术特点:两次请求,两次响应,地址栏变化,不能共享 request 数据(但可以通过 URL 参数或 session 传递)。
使用场景:登录后跳转到首页、跳转到外部网站、防止表单重复提交。
二、类比理解(餐厅点餐版 + 快递版)
转发:你去餐厅点一份鱼香肉丝,服务员 A 发现需要配菜,于是把单子内部转给服务员 B,B 做完直接端给你。你只接触了一次服务员。
重定向:你去餐厅点鱼香肉丝,服务员 A 说“我们店不做这个,隔壁店有”,于是你自己走出去到隔壁再点一次。你接触了两次服务员。
快递版:转发 = 快递站内部把包裹转给另一个快递员,你只查一次单号;重定向 = 快递站告诉你“这个包裹不归我管,请去另一个站点取”,你必须重新查询。
三、代码实战(基于你的 Servlet 项目)
-
请求转发示例
java
@WebServlet("/forwardDemo")
public class ForwardServlet extends HttpServlet {
protected void doGet(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
// 在 request 中存入数据(只能在一次请求内共享)
req.setAttribute("msg", "我是转发过来的数据");
req.setAttribute("user", "张三");// 转发到另一个 Servlet 或 JSP 页面
// 注意:路径以 / 开头表示项目根路径
req.getRequestDispatcher("/show.jsp").forward(req, resp);// 转发后,后续代码仍然会执行(但一般不会再输出内容)
System.out.println("转发完成,这行代码会执行,但不会影响页面输出");
}
}
show.jsp 接收数据:
jsp
<%@ page contentType="text/html;charset=UTF-8" %>
转发目标页面
消息:${msg}
用户:${user}
请求方式:${pageContext.request.method}
2. 重定向示例 java @WebServlet("/redirectDemo") public class RedirectServlet extends HttpServlet { protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws IOException { // 注意:重定向不能直接共享 request 数据 // 如果想传数据,可以放到 session 或 URL 参数里 req.getSession().setAttribute("info", "重定向带数据");// 重定向到外部网站
// resp.sendRedirect("https://www.baidu.com");
// 重定向到本项目的另一个路径(需要加项目上下文路径)
String contextPath = req.getContextPath(); // 例如 /MyWeb
resp.sendRedirect(contextPath + "/login.jsp");
// 注意:重定向后,后续代码仍然会执行
System.out.println("重定向完成,这行代码依然会执行");
}
}
四、常见错误与注意事项
错误1:转发后继续向 response 输出内容
现象:可能会抛出 IllegalStateException
解决:转发前确保没有提交响应(没有 flush),或者把输出代码放在转发之前。
错误2:重定向使用了相对路径导致 404
解决:使用 req.getContextPath() 加上绝对路径。
错误3:混淆了转发和重定向的方法名
转发:req.getRequestDispatcher("目标").forward(req,resp)
重定向:resp.sendRedirect("目标")

六、一个综合案例:模拟用户登录后的跳转
java
@WebServlet("/login")
public class LoginServlet extends HttpServlet {
protected void doPost(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
String username = req.getParameter("username");
String password = req.getParameter("password");
// 模拟验证(实际应该查数据库)
if ("admin".equals(username) && "123".equals(password)) {
// 登录成功:使用重定向到主页(防止表单重复提交)
req.getSession().setAttribute("loginUser", username);
resp.sendRedirect(req.getContextPath() + "/index.jsp");
} else {
// 登录失败:使用转发留在登录页,并显示错误信息
req.setAttribute("error", "用户名或密码错误");
req.getRequestDispatcher("/login.jsp").forward(req, resp);
}
}
}




浙公网安备 33010602011771号