1. 概述

在Java Servlet开发中,我们经常需要将请求委托给其他资源处理。这时有两种选择:转发(Forward)重定向(Redirect)。本文将深入探讨这两种机制的实现方式、核心差异及最佳实践。

2. Maven依赖

首先添加Servlet核心依赖:

<dependency>
    <groupId>jakarta.servlet</groupId>
    <artifactId>jakarta.servlet-api</artifactId>
    <version>6.1.0-M2</version>
</dependency>

最新版本可查阅Maven中央仓库

3. 转发机制

直接看代码实现:

protected void doGet(HttpServletRequest req, HttpServletResponse resp) {
    RequestDispatcher dispatcher = getServletContext()
      .getRequestDispatcher("/forwarded");
    dispatcher.forward(req, resp);
}

核心逻辑

  1. 从父Servlet获取RequestDispatcher对象
  2. 指向目标服务器资源/forwarded
  3. 执行转发操作

当客户端访问http://localhost:8081/hello?name=Dennis时:

  • 请求在服务器内部被转发到/forwarded
  • 浏览器地址栏保持不变
  • ✅ 原始请求参数(如name=Dennis)自动保留

4. 重定向机制

重定向的实现更简洁:

protected void doGet(HttpServletRequest req, HttpServletResponse resp){
    resp.sendRedirect(req.getContextPath() + "/redirected");
}

核心逻辑

  1. 直接使用原始response对象
  2. 构造目标URL(注意添加getContextPath()
  3. 发送重定向指令

当客户端访问http://localhost:8081/welcome?name=Dennis时:

  • 服务器返回302状态码和Location头
  • 浏览器自动跳转到http://localhost:8081/redirected
  • ❌ 原始请求参数丢失

Spring框架中的重定向实现可参考专属文章

5. 核心差异对比

特性 转发 (Forward) 重定向 (Redirect)
处理位置 服务器内部完成 客户端浏览器执行跳转
URL可见性 地址栏不变 地址栏显示新URL
请求对象 复用原始request/response 创建全新request对象
参数传递 ✅ 自动保留所有参数 ❌ 参数丢失(需手动处理)
典型场景 内部资源调度 表单提交后跳转、登录重定向
性能开销 ⚠️ 较低(单次请求) ⚠️ 较高(两次HTTP往返)

关键踩坑点

  • 重定向后若需保留参数,必须通过HttpSession手动存储
  • 转发路径需以/开头(相对于应用根路径)
  • 重定向URL必须包含getContextPath()避免路径错误

6. 最佳实践总结

选择机制时遵循以下原则:

使用转发(Forward)的场景

  • 需要复用原始请求参数
  • 执行内部业务逻辑跳转
  • 不希望用户感知URL变化
  • ✅ 例如:MVC框架中Controller到View的跳转

使用重定向(Redirect)的场景

  • 需要更新浏览器地址栏
  • 避免表单重复提交(Post/Redirect/Get模式)
  • 跨应用跳转
  • ✅ 例如:登录成功后跳转到首页

示例代码已上传至GitHub仓库


原始标题:Servlet Redirect vs Forward