概览
| 特性 | 客户端跳转 | 服务器端跳转 |
|---|---|---|
| 核心原理 | 服务器向浏览器返回一个 302 状态码和新的 Location,浏览器收到后重新发起一个新请求访问新页面。 |
服务器在内部直接将请求转发给另一个资源,浏览器对此毫不知情。 |
| 实现方式 | response.sendRedirect() |
<jsp:forward> 或 RequestDispatcher.forward() |
| URL 地址栏 | 会改变为新的 URL 地址。 | 不会改变,始终显示原始请求的 URL。 |
| 请求与响应 | 两个独立的请求和响应,第一个请求结束,第二个请求开始。 | 同一个请求和响应在服务器内部传递。 |
| 数据共享 | 不能直接共享 request 中的数据,因为第二次请求是全新的,数据需要通过 URL 参数 (?key=value) 或 session 传递。 |
可以共享 request 中的数据,因为是在同一个请求内处理。 |
| 性能 | 相对较慢,因为浏览器需要重新发起网络请求。 | 相对较快,因为不涉及网络往返。 |
| 适用场景 | 登录成功后跳转到主页、跨域跳转、需要改变 URL 的情况(如搜索页)。 | 页面布局(如头部、主体、底部)、条件判断后跳转、MVC 模式中跳转到视图。 |
客户端跳转
这种方式通过 HTTP 重定向实现,最常见的方式是使用 response.sendRedirect()。

核心方法
response.sendRedirect(String location)
示例代码
假设我们有两个 JSP 文件:
login.jsp: 登录页面welcome.jsp: 登录成功后的欢迎页面
a) login.jsp (登录表单)
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">登录页面</title>
</head>
<body>
<h2>用户登录</h2>
<form action="login_process.jsp" method="post">
用户名: <input type="text" name="username"><br>
密码: <input type="password" name="password"><br>
<input type="submit" value="登录">
</form>
</body>
</html>
b) login_process.jsp (处理登录逻辑并跳转)

<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<%@ page import="java.net.URLEncoder" %>
<%
// 1. 获取表单提交的数据
String username = request.getParameter("username");
String password = request.getParameter("password");
// 2. 模拟简单的验证逻辑
if ("admin".equals(username) && "password".equals(password)) {
// 登录成功,使用 sendRedirect 进行客户端跳转
// 可以在 URL 后面通过 ?key=value 的方式传递数据
String redirectUrl = "welcome.jsp?user=" + URLEncoder.encode(username, "UTF-8");
response.sendRedirect(redirectUrl);
} else {
// 登录失败,可以跳转到错误页面或返回登录页
out.println("<script>alert('用户名或密码错误!'); window.location.href='login.jsp';</script>");
}
%>
注意: 如果要通过 URL 传递中文等特殊字符,最好使用 URLEncoder.encode() 进行编码,防止乱码。
c) welcome.jsp (欢迎页面)
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">欢迎页面</title>
</head>
<body>
<h1>欢迎您!</h1>
<!--
由于是客户端跳转,数据通过 request 参数传递。
注意:request 对象在这里是新的请求,所以需要从参数中获取。
-->
<p>欢迎您, <%= request.getParameter("user") %>!</p>
<p>您可以通过查看浏览器地址栏发现,URL 已经从 login_process.jsp 变成了 welcome.jsp。</p>
</body>
</html>
服务器端跳转
这种方式也称为“请求转发”,服务器将当前请求的处理权交给另一个资源处理,客户端浏览器完全不知道这个过程。
核心方法
- JSP 动作标签:
<jsp:forward> - Servlet API:
request.getRequestDispatcher("url").forward(request, response)
示例代码
我们使用同样的场景,但这次使用服务器端跳转。

a) login_forward.jsp (处理登录逻辑并转发)
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<%
// 1. 获取表单提交的数据
String username = request.getParameter("username");
String password = request.getParameter("password");
// 2. 模拟简单的验证逻辑
if ("admin".equals(username) && "password".equals(password)) {
// 登录成功,使用 requestDispatcher 进行服务器端跳转(转发)
// 数据可以直接存入 request 属性中,在新页面直接获取
request.setAttribute("loggedInUser", username);
// 获取转发器,并执行转发
// 路径是相对于当前 webapp 根目录的
request.getRequestDispatcher("welcome_forward.jsp").forward(request, response);
// forward() 方法执行后,当前页面的代码就停止执行了,下面的代码不会被执行
// out.println("这一行不会被执行到");
} else {
// 登录失败,可以转发到一个错误页面
request.setAttribute("errorMessage", "用户名或密码错误!");
request.getRequestDispatcher("error.jsp").forward(request, response);
}
%>
注意: forward() 方法执行后,JSP 容器会立即停止当前页面的执行,并将控制权交给目标页面。forward() 之后的代码(out.println())不会被执行。
b) welcome_forward.jsp (欢迎页面)
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">欢迎页面 (服务器端跳转)</title>
</head>
<body>
<h1>欢迎您!</h1>
<!--
由于是服务器端跳转(转发),数据通过 request 属性传递。
这里的 request 对象和 login_forward.jsp 是同一个。
-->
<p>欢迎您, <%= request.getAttribute("loggedInUser") %>!</p>
<p>请查看浏览器地址栏,URL 仍然是 login_forward.jsp,并没有改变。</p>
</body>
</html>
c) error.jsp (错误页面)
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">登录错误</title>
</head>
<body>
<h1>登录失败</h1>
<p style="color: red;"><%= request.getAttribute("errorMessage") %></p>
<p><a href="login.jsp">返回登录页</a></p>
</body>
</html>
总结与最佳实践
-
何时使用
sendRedirect(客户端跳转)?- 需要改变 URL 时:登录成功后跳转到主页,URL 从
/login变成/home。 - 跨域或跨应用跳转:当需要跳转到另一个完全不同的网站或 Web 应用时。
- 防止表单重复提交:在提交表单后进行重定向,如果用户刷新页面,浏览器会提示“重新提交表单数据吗?”,此时重新提交的是 GET 请求,不会重复执行业务逻辑。
- 退出登录:通常需要清除 session 并跳转到登录页。
- 需要改变 URL 时:登录成功后跳转到主页,URL 从
-
何时使用
forward(服务器端跳转)?- 需要共享 request 数据时:这是最核心的原因,在 MVC 架构中,控制器处理完业务逻辑后,将数据存入
request,然后转发到 JSP 视图进行展示。 - 不希望改变 URL 时:一个网站的所有页面都通过一个主入口(如
index.jsp)来控制,根据参数转发到不同的子页面,但用户看到的始终是index.jsp。 - 提高性能:避免了一次不必要的网络往返。
- 需要共享 request 数据时:这是最核心的原因,在 MVC 架构中,控制器处理完业务逻辑后,将数据存入
在现代的 Web 开发中(尤其是基于 MVC 框架如 Spring MVC),服务器端跳转是构建视图层的标准做法,因为它能很好地在控制器和视图之间传递数据,而客户端跳转则更多地用于流程控制,如登录、注册、退出等场景。
