0%

请求转发和重定向

请求转发与重定向:Java Web 中的页面跳转机制

在 Java Web 开发中,页面跳转是常见需求,主要通过请求转发(Forward)请求重定向(Redirect) 两种方式实现。它们在原理、使用场景和特性上有显著区别,理解这些差异对构建高效的 Web 应用至关重要。本文将详细解析两种机制的实现、区别及适用场景。

请求转发(Forward)

请求转发是指服务器收到客户端请求后,将请求 “转发” 给内部另一个资源(如 Servlet、JSP)处理,最终由目标资源生成响应返回给客户端。整个过程在服务器内部完成,客户端感知不到中间转发步骤。

实现方式

通过 HttpServletRequestgetRequestDispatcher() 方法获取 RequestDispatcher 对象,再调用其 forward() 方法实现转发:

1
2
// 请求转发到 /targetServlet
request.getRequestDispatcher("/targetServlet").forward(request, response);

RequestDispatcher 接口

RequestDispatcher 由 Servlet 容器创建,用于封装目标资源并提供转发或包含功能,核心方法:

  • forward(request, response):将请求转发到目标资源,目标资源的响应会直接返回给客户端。
  • include(request, response):将目标资源的响应包含到当前响应中(如页面片段复用)。

接口中定义了多个常量(如 FORWARD_REQUEST_URIINCLUDE_CONTEXT_PATH),用于在转发 / 包含时传递原始请求的元信息(如 URI、路径等)。

转发的特性

  • 一次请求:客户端仅发起一次请求,服务器内部转发,requestresponse 对象在整个过程中复用。
  • 地址栏不变:客户端地址栏显示的仍是初始请求的 URL,不显示目标资源的路径。
  • 共享 request 数据:转发过程中,requestattribute 可在多个资源间共享(通过 setAttribute/getAttribute)。
  • 仅限内部资源:只能转发到当前 Web 应用内的资源(如 /target.jsp/servlet/demo),无法跨应用或跨域。
  • 路径规则:转发路径中的 / 代表当前 Web 应用的根目录(如 /target 等价于 http://localhost:8080/应用名/target)。

示例:转发时共享数据

1
2
3
4
5
6
// 源 Servlet
request.setAttribute("user", "zhangsan"); // 设置共享数据
request.getRequestDispatcher("/targetServlet").forward(request, response);

// 目标 Servlet
String user = (String) request.getAttribute("user"); // 获取共享数据(输出 "zhangsan")

请求重定向(Redirect)

请求重定向是指服务器收到客户端请求后,返回一个特殊的响应(状态码 302 + Location 头),告知客户端 “请重新访问 Location 指向的 URL”。客户端收到响应后,会主动发起第二次请求,访问新的 URL。

实现方式

通过 HttpServletResponsesendRedirect() 方法直接指定重定向目标 URL:

1
2
// 重定向到 /login.jsp
response.sendRedirect("/login.jsp");

也可手动设置状态码和 Location 头实现同样效果:

1
2
response.setStatus(HttpServletResponse.SC_FOUND); // 302 状态码
response.setHeader("Location", "/login.jsp");

重定向的特性

  • 两次请求:客户端先发起一次请求,收到重定向响应后再发起第二次请求,两次请求使用不同的 request 对象。

  • 地址栏变化:客户端地址栏会更新为 Location 指向的 URL。

  • 不共享数据:两次请求是独立的,requestattribute 无法传递(需通过 URL 参数或会话共享数据)。

  • 跨域 / 跨应用:可重定向到任意 URL(如其他 Web 应用、外部网站 https://example.com)。

  • 路径规则:重定向路径中的 / 代表服务器的根目录(如 Tomcat 中 / 等价于 http://localhost:8080/),需通过 request.getContextPath() 拼接当前应用路径:

    1
    2
    // 正确重定向到当前应用内的 /user 路径
    response.sendRedirect(request.getContextPath() + "/user");

示例:重定向时传递参数

1
2
3
4
5
// 重定向并通过 URL 参数传递数据
response.sendRedirect("/user?name=zhangsan");

// 目标资源中获取参数
String name = request.getParameter("name"); // "zhangsan"

请求转发与重定向的核心区别

特性 请求转发(Forward) 请求重定向(Redirect)
请求次数 1 次(服务器内部转发) 2 次(客户端重新请求)
地址栏 URL 不变(显示初始请求 URL) 变化(显示目标 URL)
request 共享 共享(同一对象) 不共享(两次请求是不同对象)
跳转范围 仅限当前 Web 应用内 可跨应用、跨域
路径中的 / 含义 代表当前 Web 应用根目录(/应用名/ 代表服务器根目录(http://主机:端口/
响应头提交时机 转发前未提交响应头 立即提交响应头(后续无法修改响应头)
适用场景 内部资源跳转(如 MVC 中控制器跳视图) 登录后跳转、避免表单重复提交、跨应用跳转

适用场景分析

  1. 请求转发的典型场景
    • MVC 模式中,控制器(Servlet)处理完业务后,转发到视图(JSP)渲染页面。
    • 多个组件协作处理同一请求(如权限校验 Servlet 转发到业务处理 Servlet)。
    • 需要共享 request 数据时(如传递处理结果到视图)。
  2. 请求重定向的典型场景
    • 用户登录成功后跳转到首页(避免刷新页面导致重复提交登录表单)。
    • 访问未授权资源时,重定向到登录页。
    • 跨应用跳转(如从电商系统跳转到支付系统)。

常见问题与最佳实践

  1. 路径拼接问题

    • 转发时,推荐使用相对路径或 / 开头的应用内路径(如 /target)。

    • 重定向时,必须通过request.getContextPath()拼接应用路径,避免部署路径变化导致错误:

      1
      2
      3
      4
      // 错误方式(依赖部署路径)
      response.sendRedirect("/app/user");
      // 正确方式(动态获取应用路径)
      response.sendRedirect(request.getContextPath() + "/user");
  2. 响应头提交后修改的异常

    • 重定向后无法再修改响应头或响应体(会抛出 IllegalStateException)。
    • 转发前若已写入响应体(如 out.print()),转发会失败(需确保转发前未提交响应)。
  3. 避免表单重复提交

    • 表单提交后,使用重定向到结果页(而非转发),防止用户刷新页面导致重复提交

欢迎关注我的其它发布渠道

表情 | 预览
快来做第一个评论的人吧~
Powered By Valine
v1.3.10