同样是“跳转”,为何forward地址栏不变,redirect会变?

故事场景:在大型办公楼里办业务

你(浏览器/用户 )今天要去"市政府办公大楼"(服务器 )办理一项业务。你手裡拿著一份填好的"申请表 "(HttpServletRequest)。

方式一:forward --- "内部转交,您请稍候"

这是一种对你透明、在内部完成的服务方式。

  • 流程:

      1. 你来到大楼前台(比如 ForwardServlet),把你的"申请表"递给了接待员A。
      1. 接待员A看了一眼,说:"好的,我受理了。但这个业务需要后台的档案室(FinalDestinationServlet)处理。您在这儿稍等,别动。"
      1. 然后,接待员A拿着你的那份原封不动的申请表 ,甚至可能在上面用便签加了一条批注(request.setAttribute(...)),亲自跑到了大楼内部的档案室,把表交给了档案员B。
      1. 档案员B处理完,将最终结果通过接待员A交还给你。
  • 你的体验:

    • 地址栏不变:从始至终,你都站在前台,你的物理位置没有变过。你手机导航的目的地(浏览器地址栏URL)一直显示的是"市政府前台"。

    • 一次请求:你只来了一次办公大楼。

    • 数据共享 :接待员A在你申请表上加的便签,档案员B能原封不动地看到。因为你们自始至终用的都是同一份申请表

方式二:redirect --- "地址不对,请您再去一趟"

这是一种让你自己跑腿的服务方式。

  • 流程:

      1. 你来到大楼前台(比如 RedirectServlet),把你的"申请表"递给了接待员C。
      1. 接待员C看了一眼,立刻把申请表退还给你,说:"哦!您走错地方了! 这个业务现在已经搬到街对面的'市民服务中心'(/finalDestination)去办了。这是新地址,您得自己过去一趟。"
      1. 接待员C的工作到此结束。他给了你一个"302重定向"指令。
      1. 你只好走出办公大楼,回到车里,重新导航到"市民服务中心"这个新地址 ,然后重新提交一份申请表
  • 你的体验:

    • 地址栏改变 :你 physically 移动到了新的地点,所以你的手机导航(浏览器地址栏URL)也更新成了新的地址"市民服务中心"。

    • 两次请求:你先去了"市政府",又去了"市民服务中心",这是完全独立的两次出行。

    • 数据不共享 :你在第一份申请表上精心粘贴的补充材料,在去新地点的路上弄丢了。因为你去新地点提交的是一份全新的申请表,和旧的那份毫无关系。

故事总结:

特性 forward (内部转交) redirect (请您再去一趟)
发生地点 服务器内部 ,对浏览器透明 服务器 -> 浏览器 -> 服务器
请求次数 1次 2次
地址栏URL 不变 改变
数据共享 共享 request 数据 (效率高) 不共享 request 数据 (效率低)
核心比喻 一个部门把你的材料转给另一个部门 告诉你走错门了,让你自己去另一个部门
本质 服务器帮你处理,你无感知 服务器让你自己去另一个地方
使用场景 MVC框架中,Controller处理完数据后,转发给View(JSP)进行渲染。 用户登录成功后,重定向到主页;处理完表单提交后,重定向到结果页(防止重复提交)。

一句话总结:

  • forward 是"我帮你办",发生在服务器内部,快,能带东西。

  • redirect 是"你自个儿去",发生在浏览器端,慢,两手空空地去。

核心代码

我们将用三个简化的 Servlet 来演示 forwardredirect 的行为差异,特别是它们在"地址栏变化"和"请求数据传递"上的不同。

1. 发起转发的 Servlet (ForwardServlet.java)

复制代码
// ForwardServlet.java
@WebServlet("/forwardServlet")
publicclassForwardServletextendsHttpServlet {
    protectedvoiddoGet(HttpServletRequest request, HttpServletResponse response)throws ServletException, IOException {
        System.out.println("ForwardServlet: 接待了请求,正在处理...");
        
        // forward 可以将数据放入 request 域中,传递给下一个 servlet
        request.setAttribute("message", "这是来自 ForwardServlet 的秘密文件!");
        
        System.out.println("ForwardServlet: 决定将请求 '内部转交' 给 FinalDestinationServlet。");
        
        // 获取请求分发器,并执行 forward
        RequestDispatcherdispatcher= request.getRequestDispatcher("/finalDestination");
        dispatcher.forward(request, response);
        
        // forward 之后,这里的代码不会再执行
    }
}

2. 发起重定向的 Servlet (RedirectServlet.java)

复制代码
// RedirectServlet.java
@WebServlet("/redirectServlet")
publicclassRedirectServletextendsHttpServlet {
    protectedvoiddoGet(HttpServletRequest request, HttpServletResponse response)throws ServletException, IOException {
        System.out.println("RedirectServlet: 接待了请求,正在处理...");

        // redirect 无法通过 request 域传递数据,因为它是两次不同的请求
        // 下面这行代码设置的属性将会丢失
        request.setAttribute("message", "这个秘密文件将会丢失!");

        System.out.println("RedirectServlet: 告诉浏览器 '请您去另一个地址' (FinalDestinationServlet)。");

        // 执行 redirect
        response.sendRedirect(request.getContextPath() + "/finalDestination");
    }
}

3. 最终目的地 Servlet (FinalDestinationServlet.java)

复制代码
// FinalDestinationServlet.java
@WebServlet("/finalDestination")
publicclassFinalDestinationServletextendsHttpServlet {
    protectedvoiddoGet(HttpServletRequest request, HttpServletResponse response)throws ServletException, IOException {
        System.out.println("FinalDestinationServlet: 我是最终目的地!");

        // 尝试从 request 域中获取数据
        Stringmessage= (String) request.getAttribute("message");

        response.setContentType("text/html;charset=UTF-8");
        PrintWriterout= response.getWriter();
        out.println("<h1>欢迎来到最终目的地!</h1>");
        
        if (message != null) {
            out.println("<p>我收到了秘密文件: " + message + "</p>");
            out.println("<p><b>说明:</b> 这是通过 forward 过来的,因为 request 对象是同一个。</p>");
        } else {
            out.println("<p>我没有收到任何秘密文件。</p>");
            out.println("<p><b>说明:</b> 这是通过 redirect 过来的,浏览器发起了全新的请求,旧 request 的数据丢失了。</p>");
        }
    }
}
相关推荐
怕浪猫43 分钟前
长会话不崩盘:DeepSeek Harness 的上下文压缩与目标管理策略
面试·github·agent
DogDaoDao2 小时前
SimToolReal 解读:用“物体中心“视角重新定义灵巧工具操作
人工智能·机器人·github·关键点·人形机器人·gpt-4o·simtoolreal
99316666 小时前
一个人用 AI 的困局:它从不反对你,所以我让 5 个 AI 开了场圆桌会议
github·deepseek
其实防守也摸鱼7 小时前
每天一个知识点——RCE漏洞
运维·服务器·数据库·windows·安全·github·漏洞
u1301308 小时前
GitHub 热榜项目:日榜(2026-09-12)
github
TunerT_TQ8 小时前
Netflix|一个时代的终结:Hystrix静态工程评测,兼谈微服务容错范式的代际迁移
开源·github·资讯
m4Rk_9 小时前
【论文阅读】Agent 记忆机制(68):Memp——把历史轨迹沉淀为可检索、可纠错的程序性记忆
论文阅读·人工智能·学习·开源·github
峰向AI10 小时前
腾讯开源的AI管理的瑞士军刀:让团队经验自动传承
github
Howie_052612 小时前
AI-test-agent(一)刚入门测试也能读懂:一个基于 LangGraph + Playwright 的开源测试工作台
github
zhurui_xiaozhuzaizai12 小时前
github上关于节省token的项目一览,上下文压缩,节省token,agent优化skill,热门项目
人工智能·深度学习·github