← 返回题目列表

请求转发 forward 和重定向 redirect 有什么区别?

高频 简单 第 1 / 23 题 更新于 2026/07/25
forwardredirectHTTPServlet

简化版

forward(请求转发)服务器内部转发——同一次请求在服务端交给另一个资源处理,浏览器地址栏不变,只有一次 HTTP 请求,可以共享 request 里的属性。redirect(重定向) 是服务器返回 3xx 状态码 + Location 头,让浏览器发起一次全新的请求去访问新地址,地址栏会改变,至少两次请求,request 属性丢失(要靠 URL 参数、Session、Cookie 或 Flash 传状态)。一句话:forward 是服务端内部换处理者,redirect 是让浏览器重新请求新地址

详细版

forward vs redirect 对比:

维度forward(转发)redirect(重定向)
发生位置服务器内部客户端(浏览器)
请求次数1 次≥ 2 次
地址栏不变(还是原 URL)改变(变成新 URL)
数据共享共享同一 request(可用 attribute 传数据)request 丢失,需 URL/Session/Cookie/Flash
可达范围只能转发到当前应用内资源可跳转到任意 URL(站内/站外)
状态码无(仍是原请求的最终响应)3xx(301/302/303/307)+ Location
性能少一次网络往返多一次网络往返

代码对比(Servlet):

// forward:服务端内部转发
request.getRequestDispatcher("/WEB-INF/view/result.jsp").forward(request, response);

// redirect:让浏览器重新请求
response.sendRedirect("/order/success");   // 返回 302 + Location

完整版教学

一、请求次数不同(本质区别)

这是理解两者的钥匙:

  • forward 只有一次 HTTP 请求。浏览器发一个请求,服务端内部把它「交接」给另一个资源(Servlet/JSP)处理,浏览器全程不知道服务端内部换了处理者——它只发了一次请求、收到一个响应。
  • redirect 至少两次 HTTP 请求。浏览器发第一个请求,服务端不直接处理,而是回一个 302/303 响应 + Location: 新地址;浏览器收到后,自动再发第二个请求去访问 Location 指定的新地址,拿到最终结果。

「一次 vs 两次请求」派生出下面所有区别。

维度forwardredirect
HTTP 往返1 次至少 2 次
浏览器是否感知不感知服务端内部转发感知并按 Location 重新请求
地址栏保持原 URL变为新 URL
request attribute保留丢失
典型用途服务器内部视图渲染登录跳转、提交后结果页、跨站跳转
forward:
Browser --GET /a----------> Server
Browser <--200 from /b----- Server 内部转发到 /b,地址栏仍是 /a

redirect:
Browser --POST /submit----> Server
Browser <--303 Location=/ok Server
Browser --GET /ok---------> Server
Browser <--200------------- Server,地址栏变为 /ok

二、地址栏与刷新行为

  • forward 后地址栏不变:因为浏览器压根不知道服务端内部转发了,它看到的还是最初请求的 URL。此时刷新页面 = 重复最初的请求
  • redirect 后地址栏改变:浏览器真的去访问了新地址,地址栏显示新 URL。刷新 = 重新请求新地址

这解释了「表单提交后为什么常用 redirect」(PRG 模式,Post-Redirect-Get):如果用户 POST 提交订单后用 forward 直接返回结果页,地址栏还是提交的 URL,用户一刷新就会重复提交(重复下单);改用 redirect 到一个 GET 的结果页,地址栏变成结果页 URL,刷新只是重新 GET 结果页,不会重复提交。这是防重复提交的经典手段。

记忆钩子:forward 是“服务端内部交接”,redirect 是“浏览器重新出发”。只要浏览器重新出发,地址栏、request、请求方法语义都会跟着变化。

三、数据传递方式

  • forward 共享同一个 request:因为是同一次请求,可以在转发前往 requestsetAttribute,转发后的资源用 getAttribute 取到。这是 MVC 里 Controller 把数据放 request、forward 到视图渲染的常用方式。
  • redirect 是新请求,原 request 数据全丢:新请求有自己独立的 request 对象,拿不到旧 request 的 attribute。要跨 redirect 传数据,只能用:URL 查询参数?id=1)、SessionCookie、或框架提供的 FlashMap / RedirectAttributes(Spring MVC 的 Flash 属性,本质是把数据临时存 Session、重定向后取一次就删)。

四、可达范围与安全

  • forward 只能转发到当前 Web 应用内部的资源——因为它是容器内部调度,跳不出这个应用。
  • redirect 返回的是客户端可访问的 URL,所以能跳到站内任意路径,也能跳到外部网站

redirect 的这个能力带来一个安全风险——开放重定向(Open Redirect):如果重定向的目标 URL 来自用户输入(如 ?redirect=http://evil.com)且未校验,攻击者可以构造链接把用户重定向到钓鱼网站。防护:重定向目标只允许站内相对路径白名单域名,不要直接用未校验的用户输入做重定向目标。

五、状态码与语义

redirect 会返回 3xx 状态码 + Location 响应头,常见的:

  • 301:永久重定向(浏览器/搜索引擎会记住,下次直接访问新地址,SEO 权重转移)。
  • 302:临时重定向。
  • 303(See Other):POST 后跳转常用,明确让浏览器用 GET 访问新地址(PRG 模式)。
  • 307:临时重定向,但保持原请求方法(POST 还是 POST)。

forward 对客户端而言仍表现为原请求的最终响应,没有额外状态码。

一个数字场景:用户提交订单 POST /orders,服务端处理耗时 80ms。用 forward 返回成功页时,总共 1 次请求;用户刷新会再次 POST,可能再创建 1 笔订单。用 redirect 时会多 1 次网络往返,例如再花 30ms GET /orders/123/success,但刷新只重复 GET 成功页,不会重复执行业务写操作。这 30ms 往返换来的是正确的业务语义。

六、性能不是主要决策依据

forward 少一次网络往返(不用浏览器再发一次请求),理论上更省。但性能不该是选择的主要依据——应该看语义

  • 内部视图渲染(Controller 把数据交给 JSP/模板渲染)→ 用 forward
  • 流程跳转、需要改变 URL、防重复提交(登录后跳首页、提交后跳结果页、权限不足跳登录页)→ 用 redirect

为了省一次请求而牺牲正确语义(比如该用 redirect 防重复提交却用了 forward)是不值得的。

七、常见误区与追问

  • 误区:forward 是浏览器跳转。 forward 是服务端内部转发,浏览器不知道换了处理资源,所以地址栏不会变。
  • 误区:redirect 能保留 request attribute。 redirect 是全新的 HTTP 请求,原 request 对象结束后就不存在了,要用 URL、Session、Cookie 或 Flash 属性传递跨请求数据。
  • 追问:为什么表单提交后推荐 PRG? POST 成功后 redirect 到 GET 结果页,刷新只重复 GET,不会重复执行提交动作。
  • 追问:302、303、307 的区别怎么答? 302 常表示临时跳转,303 明确让客户端用 GET 访问 Location,307 要求保持原方法和请求体。
  • 误区:redirect 目标可以直接使用用户传入的 URL。 这会产生开放重定向风险,应限制为站内相对路径或可信白名单域名。
  • 追问:内部 JSP 渲染为什么常用 forward? JSP 通常放在 WEB-INF 下不允许浏览器直接访问,Controller 可以把同一次 request 的数据转发给 JSP 渲染。

八、加强记忆

forward(转发)= 服务端内部换处理者1 次请求、地址栏不变、共享同一 request(可用 attribute 传数据)、只能转当前应用内、刷新会重复原请求redirect(重定向)= 让浏览器重新请求新地址≥2 次请求、返回 3xx+Location、地址栏改变、request 数据丢失(需 URL/Session/Cookie/Flash 传)、可跳任意 URL、刷新是新地址表单提交后用 redirect(PRG 模式)防重复提交(forward 会刷新重复提交)。redirect 目标来自用户输入要防开放重定向(白名单/相对路径)。选择看语义(内部渲染用 forward、流程跳转/改 URL 用 redirect),不是看性能。