ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

请求转发与重定向深度剖析:从HTTP协议到工程实践

请求转发与重定向深度剖析:从HTTP协议到工程实践 1. 背景与问题场景1.1 为什么每个后端开发者都要面对这个选择先说个我实际遇到的场景。之前在做一个小商城系统的登录模块时前端同事拿着接口文档跑过来问为什么有的接口返回之后浏览器地址栏会变有的不会为什么有的接口返回之后要重新发一次请求有的不用当时我意识到很多人做了一年两年后端天天写response.sendRedirect()或者request.getRequestDispatcher().forward()但真要被问到这两者底层到底差在哪多半是卡壳的。实际上请求重定向redirect和请求转发forward是Web开发里最基础也最容易混淆的一对概念。无论是Java Servlet、Spring MVC、Struts还是Python Flask、Node.js Express凡是走HTTP协议的Web应用都绕不开这两个操作。它们决定了请求在客户端和服务器之间怎么跳转、参数怎么传递、浏览器地址栏怎么变化甚至直接影响你应用的性能和安全设计。这篇文章我准备把两者彻底讲透从最底层的HTTP协议行为差异到Servlet/Spring等主流框架里的具体用法再到参数传递、绝对路径与相对路径、性能对比、常见坑点一次性梳理完。如果你是一个刚入行的后端开发看完能直接上手如果你已经写了两三年代码但从来没认真抠过这个细节这遍刷完你会理解很多以前靠背结论才记得住的规则。1.2 从一个现象聊起地址栏到底变不变先记一个最直观的区分方法请求转发整个过程中浏览器只发出一次请求服务器内部把请求转给另一个资源处理浏览器地址栏不会发生变化请求重定向服务器会返回一个3xx状态码告诉浏览器“你再去访问另一个地址”浏览器收到后会重新发起一次全新的请求地址栏会变成新的URL。这个差异看起来简单但它背后是整个HTTP协议语义的不同。转发是服务器内部行为对浏览器完全透明重定向是浏览器和服务器之间的两次完整交互。后端面试里最常问的“forward和redirect有什么区别”本质上就是在考察你是不是真正理解HTTP请求-响应模型而不是只背了几个API。下面我用一个餐厅的类比帮你建立直觉你去一家餐厅吃饭点了一道厨房里没有的菜服务员去后厨问了大厨大厨说隔壁店有这道菜——转发就好比服务员直接跑到隔壁店把菜端回来给你你从头到尾只去了一家餐厅重定向就好比服务员告诉你“你出门右转去那家店”你得自己重新走一趟再点一次菜。类比成立接下来我们进入正题从HTTP协议这个底层视角来拆解。2. 底层原理拆解HTTP协议视角的完整交互过程2.1 请求转发的完整时序请求转发发生在服务器内部。以Java Servlet为例当你调用RequestDispatcher.forward()时容器比如Tomcat会直接在当前服务器内部找到目标资源把当前请求对象ServletRequest和响应对象ServletResponse原封不动地传递过去。这里有个关键点整个过程中只有一个HTTP请求服务器只返回一次HTTP响应。时序上大概是这样的浏览器发起GET /login请求到Servlet A。Servlet A内部执行request.getRequestDispatcher(/home).forward(request, response)。Servlet容器将请求转交给Servlet B处理Servlet B写入响应内容。最终浏览器收到的响应是Servlet B生成的响应体整个过程中浏览器的URL始终是/login。从HTTP报文层面看浏览器自始至终只发送了一个请求包接收了一个响应包。中间Servlet A到Servlet B的跳转是Tomcat容器内部的函数调用对浏览器完全不可见。这也是为什么转发的地址栏不会变。需要注意转发时的请求对象是同一个。这意味着Servlet A往request.setAttribute()放的任何数据Servlet B都能通过request.getAttribute()取到。这一点是转发最核心的实用价值像MVC模式中Controller把查询结果放进request然后转发到JSP渲染靠的就是这个机制。2.2 请求重定向的完整时序重定向则是另一个故事。当你调用response.sendRedirect(/home)时服务器会先返回一个302状态码的响应同时在响应头Location字段写入目标URL。浏览器接收到这个302响应后会解析Location头然后重新发起一次全新的HTTP请求到目标地址。完整的时序是这样的浏览器发起GET /login请求到Servlet A。Servlet A执行response.sendRedirect(/home)服务器返回HTTP响应状态码302Location: /home。浏览器收到302自动发起第二次请求GET /home。服务器上的Servlet B处理第二次请求并返回响应。浏览器最终显示/home的响应内容地址栏也变为/home。也就是说一次重定向的完整交互过程包含两次HTTP请求和两次HTTP响应。第一次响应的内容基本是空的真正有用的信息都在状态码和Location头里。这里有个浏览器行为上的细节值得注意浏览器收到302/301等重定向状态码时会自动跟随Location头去发第二次请求用户是无感知的。大部分人点了个链接看到页面跳转了但不知道背后其实发生了两次请求。另外提一嘴302是“临时重定向”语义是“资源临时在别处”301是“永久重定向”语义是“资源永久迁移了”。sendRedirect默认使用302但很多框架也允许你指定返回301。搜索引擎的SEO就特别在意301和302的区别301会转移页面权重302不会。当然这是另一个话题了。2.3 状态码与响应头对比从HTTP报文这个层面两者最本质的区别可以整理成一张极简对比对比维度请求转发 forward请求重定向 redirectHTTP请求次数1次2次HTTP响应次数1次2次首次响应状态码200正常处理301或302首次响应是否有Location头无有指向新地址浏览器是否重新发请求否是对浏览器是否透明完全透明不透明地址栏是否变化不变变为新URL能否跨域跳转不能可以能否访问WEB-INF下资源可以不可以这张表建议收藏面试前翻一遍基本概念就稳了。接下来我们讲讲在真实代码里怎么写以及不同框架里的写法差异。毕竟只懂原理不会写等于纸上谈兵。3. 代码实操Servlet、Spring MVC、Spring Boot中的具体写法3.1 Java Servlet原生写法先看最基础的Servlet API写法这是理解一切框架封装的根基。请求转发WebServlet(/login) public class LoginServlet extends HttpServlet { protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { // 处理业务逻辑比如查询用户信息 User user userService.findByName(zhangsan); // 把数据放到request作用域 request.setAttribute(user, user); // 转发到JSP页面渲染 RequestDispatcher dispatcher request.getRequestDispatcher(/user/detail.jsp); dispatcher.forward(request, response); } }请求重定向WebServlet(/login) public class LoginServlet extends HttpServlet { protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { // 比如登录成功后跳转到首页 response.sendRedirect(/home); } }这两种写法看起来都很简单但有几个细节新手特别容易踩坑第一getRequestDispatcher()的路径必须以/开头这个/是相对于当前Web应用上下文根的不是相对于服务器根的。假设你的应用部署在http://localhost:8080/myapp那么/user/detail.jsp实际访问的是http://localhost:8080/myapp/user/detail.jsp。第二sendRedirect()的参数可以写相对路径也可以写绝对路径但语义完全不同。写/home表示相对于上下文根的重定向写home表示相对于当前URL路径的相对重定向写http://localhost:8080/myapp/home则是完整的绝对地址。强烈建议统一用/开头或者完整的绝对URL这样最不容易出错。第三转发之后不要再写响应内容。forward()执行后Servlet容器会把响应控制权交给目标资源如果你在forward()之后又往response.getWriter()里写了内容会抛出IllegalStateException。因为响应已经提交了不能再次修改。3.2 Spring MVC与Spring Boot中的用法在Spring MVC时代写转发和重定向通常通过返回字符串来控制。转发Controller public class OrderController { GetMapping(/order/detail) public String detail(RequestParam Long orderId, Model model) { Order order orderService.findById(orderId); model.addAttribute(order, order); // 转发到视图模板比如Thymeleaf的orderDetail.html return orderDetail; } }这里返回一个视图名称并没有显式写“forward”但实际上Spring MVC内部完成的就是一次转发——请求到达Controller后又转发给Thymeleaf模板引擎去渲染HTML。整个过程中浏览器的URL不会变化。重定向Controller public class OrderController { PostMapping(/order/create) public String create(OrderForm form, RedirectAttributes attributes) { Long orderId orderService.create(form); attributes.addFlashAttribute(message, 订单创建成功); // 重定向到订单详情页 return redirect:/order/detail?orderId orderId; } }Spring MVC中只要在返回的字符串前面加上redirect:前缀就会触发真正的HTTP重定向。此时浏览器地址栏会变成/order/detail?orderId1并且会重新发起一次GET请求。这里有一个经典实践叫PRG模式Post/Redirect/Get。为什么要用PRG模式因为在传统的表单提交场景中如果你提交POST之后返回的是视图转发用户按F5刷新时浏览器会再次提交表单造成订单重复创建的严重问题。而如果提交POST后返回一个重定向浏览器会先跳转到GET请求此时刷新页面只是重新执行GET查询不会重复提交表单。几乎所有正规的电商系统都会用PRG模式来避免重复下单这就是重定向在实际业务中最有价值的应用场景之一。RedirectAttributes里的addFlashAttribute也是一个非常实用的功能。它可以把数据存到session中在重定向后的第一次请求中读取读取完毕立即清除。这样就能实现“重定向之后还能在页面上显示一条成功提示信息”的效果。如果不用flash attribute想通过重定向传递数据就只能拼到URL参数里既麻烦又会暴露数据。3.3 其他主流框架的对应写法除了Java阵营其他语言框架里同样有这两个概念只是API叫法不同。Node.js Express用res.redirect()处理重定向转发则通过next()或内部调用中间件来完成实际上Express本身的设计就是中间件链天然是转发模型的延伸app.get(/login, (req, res) { // 重定向 res.redirect(/home); });Python Flask里重定向用redirect()函数转发则通过render_template()配合模板渲染来完成from flask import redirect, url_for app.route(/login) def login(): # 重定向 return redirect(url_for(home))注意Flask的redirect()默认也是302状态码但可以手动指定return redirect(url_for(home), code301)PHP里重定向通常用header(Location: /home)转发则用include或内部的视图渲染机制。不同语言的API虽然不同但底层全部遵循HTTP协议那套语义转发是服务器内部的资源调用重定向是让浏览器重新发起请求。理解了这一点你学任何新框架时只要找到对应的API就行不需要重新理解概念。4. 两者本质区别的深入剖析与应用场景4.1 地址栏变化背后的含义很多人只记住了“转发地址栏不变重定向地址栏会变”但没想过为什么。这个现象背后的本质是URL地址代表的是“客户端所认知的资源位置”。转发时浏览器认为自己访问的还是最初那个URL服务器内部谁在处理这件事浏览器不关心重定向时服务器明确告诉浏览器“你要的东西不在这里去别处找”浏览器于是更新了自己对资源位置的认知。这个差异带来一个重要的实际影响刷新行为完全不同。如果是转发页面用户在浏览器里刷新会再次提交到原始URL如果是重定向后的页面刷新时重新请求的是新URL。放在表单提交场景里这个差异直接关系到会不会重复提交。前面提到PRG模式本质上就是在利用重定向的特性主动切断“刷新→重复提交”这条链路。还有一点转发页面如果刷新浏览器会弹出一个“确认重新提交表单”的提示用户体验很差重定向之后刷新则是普通的GET请求不会弹任何提示。别小看这个细节真正上线运营的系统这里能直接影响订单数据的正确性。4.2 参数传递与数据可见性前面已经提到转发可以通过request.setAttribute()传数据重定向则要通过URL参数或flash attribute。这个差异的根因还是因为两者的请求次数不同。转发只有一个请求所以所有数据都可以放进request作用域里跟随请求一起传递。这是MVC模式的基础——Controller把业务数据封装成Model传给View层渲染全程不走浏览器数据不会暴露在URL中也不会出现在浏览器历史记录里。重定向有两次请求第一次请求里设置的所有request attribute在第二次请求里都拿不到。想要传递数据只有三个途径拼接在URL参数里比如/order/detail?orderId1。缺点是很明显的URL会暴露参数信息有些人可能会篡改参数值。所以所有通过URL传递的参数在接收端都必须做合法性校验。放到session里重定向之后从session中读取。这种方式目前主流框架都封装好了比如Spring MVC的RedirectAttributes.addFlashAttribute()本质上就是先存session再在第二次请求时自动移除以读取。用cookie传但不常用因为cookie容量有限且每次请求都会带上影响性能。从安全角度看转发比重定向更适合传递敏感数据因为数据不会暴露在URL中。但从隔离角度看重定向反而更安全——两次请求不会共享同一个request对象某些副作用数据天然就被隔离了。4.3 跨域与路径问题请求转发只能转发到同一个Web应用内部的资源。你可以转发到/user/detail.jsp但不能转发到http://other-site.com/user/detail。因为转发是服务器内部的动作服务器只能控制自己应用内的资源。请求重定向则没有这个限制。你可以重定向到任何域名下的任何URL比如支付平台的支付页面、第三方授权登录页面、CDN上的静态资源等等。这也是为什么OAuth2授权、单点登录、支付回调这些场景全都依赖重定向——它们天然需要跨越不同的服务系统。路径方面有个经典坑点在转发时如果你用了相对路径很容易因为URL层级变化导致资源加载失败。比如你在/user/detail页面里写了一个相对路径../static/css/style.css如果这个页面是被转发过来的浏览器眼中的当前URL还是原始的/user/detail相对路径解析出来可能跟你预期的完全不一样。实际开发中前端页面上引用静态资源强烈建议使用以/开头的应用根路径写法或者干脆用模板引擎的URL拼接函数如Thymeleaf的{/static/css/style.css}这样无论请求是转发还是重定向只要浏览器地址栏的URL一致资源引用就不会出问题。4.4 性能对比与取舍从性能角度转发明显比重定向更优。理由很简单转发只有一次HTTP往返重定向有两次。HTTP往返的开销不止是网络传输时间还包括TCP连接建立如果没开启连接复用、HTTP头部解析、浏览器等待时间等。以用户点击一次按钮到页面完全加载的完整链路来看重定向通常比转发多消耗大约一次RTT往返时延。在高并发场景下如果大量请求都走重定向服务器承受的总请求量会翻倍对性能的影响会被放大。这也是为什么内部页面流转能用转发就用转发。但性能并不是唯一的考量因素。重定向的价值在于它的“无状态”特性每次重定向都是一次全新的请求服务器不需要维护转发链路的调用栈业务代码的耦合度更低。而且重定向天然支持负载均衡——第一次请求打到A服务器重定向到B服务器如果B服务器是专门处理静态资源的CDN那么动态和静态就能完全分离。所以正确的选择逻辑应该是应用内部的页面流转、Controller到View的数据传递用转发。需要跳转到外部系统、或需要改变浏览器地址栏URL、或需要避免表单重复提交用重定向。两者都能满足的场景优先转发因为更高效。4.5 浏览器历史的差异还有一个常被忽略的点浏览器历史记录。转发不会在浏览器历史中保留中间步骤因为浏览器全程只看到最初那个URL重定向则会在历史记录中留下初始URL和最终URL两个记录。意味着用户点击浏览器“后退”按钮时两种方式回到的页面位置是不同的。有些系统故意利用这个特性做页面流程控制。比如在支付成功后后端做了重定向用户按后退键回到的是支付确认页而不是支付处理页这样可以在一定程度上避免用户回退到不该去的页面。转发则没有这层“隔离”作用用户的回退轨迹是连续的可能回到不该回的表单页。4.6 两者选择的一条黄金法则聊了这么多区别我把选型逻辑总结成一条实战法则给用户看的最终URL应该是重定向后的结果用户不需要在地址栏看到中间处理页。换句话说所有“处理完毕后的成功页”用重定向“处理过程中的中间渲染页”用转发。举几个实际的例子登录成功后跳首页用重定向因为首页是用户真正要访问的资源地址栏应该显示首页地址。登录失败后显示错误信息用转发因为错误信息是临时的地址栏保持登录页。表单提交后的成功页面用重定向防止重复提交。列表页点击查询按钮后的结果展示用转发查询参数直接传给视图渲染避免URL带一串查询条件。这是我这几年做项目最核心的体会。你不需要背一堆条条框框只要抓住“用户最终该看到哪个URL”这个核心方案基本不会错。5. 容易混淆的偏门知识点与常见误区5.1 误区一转发比重定向“快”所以尽量多转发这个说法只看到了一半。转发确实省了一次HTTP往返但它也有自身的代价转发的请求链路是在服务器内部完成的整个请求期间服务器必须保持对请求的占用Servlet的调用栈更复杂。如果一次转发链路过长比如A转给BB又转给CC又转给D排查问题的难度会明显升高每层的日志关联也不如两次独立请求直观。而且转发在负载均衡环境里有陷阱。如果A服务器把请求转发到本机的Servlet B用户的请求自始至终只被A处理。假设A挂了呢整个转发链路就断了。但如果是重定向用户的第二次请求可能会被负载均衡器分流到另一台健康的服务器上反而具备了一定的容错能力。所以我的建议是应用内部的轻量级流转用转发没问题但如果是跨模块、跨系统的跳转或者涉及高可用的场景重定向反而是更稳妥的选择。5.2 误区二response.sendRedirect() 只能在GET请求里用这个想法是错的。sendRedirect()在Servlet里不论当前请求是GET还是POST都能调用。只不过浏览器收到302后自动发起的第二次请求默认是GET请求。没错这就是著名的一个坑如果用户提交的是POST表单你直接sendRedirect到一个需要POST数据的接口那第二次请求会变成GET后端接口可能匹配不到对应的处理方法返回404或405。所以重定向只适合跳转到“接受GET请求”的资源。如果跳转目标必须处理POST数据你不能用重定向要么转发要么在主请求里直接处理要么就用带签名的临时凭证让目标接口接受GET参数。5.3 误区三转发和重定向只能二选一现实中经常组合使用。一个典型场景就是前面提到的PRG模式POST请求进来后端处理完毕返回redirect:/order/detail浏览器收到302发GET请求访问/order/detail/order/detail的Controller内部再通过转发把数据传给模板渲染。整个链路里POST之后的跳转用了重定向GET响应内的数据传递用了转发。两者配合既避免了重复提交又实现了数据的安全传递。不少人对PRG模式理解不深以为重定向只是从A跳到B的一锤子买卖其实它和转发组合起来才是完整的方案。5.4 关于“重定向会不会造成死循环”这是运维和开发都关注的实际问题。如果A接口每次都302重定向到B接口而B接口又302重定向回A接口浏览器就会陷入无限跳转最终报ERR_TOO_MANY_REDIRECTS或者too many redirects。这种问题在配置session校验、登录拦截器的场景里特别常见。排查思路通常是打开浏览器的网络面板查看请求瀑布流里连续出现的302响应观察它们的Location头。如果看到两个资源互相跳转基本就是代码逻辑写岔了。我之前遇到过一例用户未登录访问受保护资源时拦截器重定向到登录页登录成功后又重定向回原资源地址。但因为登录成功后session写入的时机太晚导致每次访问原资源时仍被判定为未登录反复重定向。解决方式很简单登录后先写session再重定向或者把重定向回的资源地址改为一个不需要鉴权的确认页。5.5 浏览器缓存对重定向的影响还有一个容易被忽略的细节浏览器或中间代理可能会缓存301和302响应。301永久重定向的缓存时间是永久性的一旦浏览器缓存了之后所有访问该URL的请求都会直接走缓存的重定向结果不再询问服务器。302临时重定向默认不缓存但某些代理服务器可能会强制缓存。这会导致一个诡异的现象明明后端修改了重定向目标某些用户访问时还是跳到旧地址。解决方式如果你希望重定向目标随时可变用302如果你确定资源永久迁移了可以用301。在Spring MVC里可以通过返回ResponseEntity自定义状态码或者设置对应的缓存响应头来控制浏览器行为。6. 我踩过的几个坑与实战心得6.1 坑一转发到WEB-INF下与直接访问的区别Java Web开发中WEB-INF目录下的资源有个特点不能被浏览器直接URL访问只能通过服务器内部转发或重定向这里的重定向其实也是转发模式来访问。有些团队的页面模板放在WEB-INF下然后配置了拦截器有些人误以为只要放在WEB-INF就绝对安全其实不是——如果你在代码里用转发把请求转发到WEB-INF路径写错了还是照样报404。我的经验是WEB-INF下的页面作为视图模板使用没有问题但如果你要跳转的所谓“页面”实际上是个需要传参的动态资源用转发比重定向靠谱得多因为转发可以保持request请求内的数据完整性。用重定向去WEB-INF目录浏览器会直接404因为没有对应的公共URL映射。当年我有一个同事把登录失败的错误提示放在WEB-INF下的页面然后登录逻辑里用了response.sendRedirect(/WEB-INF/error.jsp)结果不管怎么调都是404。最后改回dispatcher.forward()才正常。这是个很经典的坑特此记录。6.2 坑二重定向后request作用域数据丢失新手最常见的困惑就是我在第一个Servlet里request.setAttribute(msg, success)sendRedirect之后第二个Servlet里request.getAttribute(msg)拿到的是null。这完全符合预期因为第二次请求是一个全新的request对象和第一次请求没有任何关系。如果确实需要传递数据首选方案是用Spring MVC的flash attribute次选方案是拼URL参数最差方案是用session硬存。为什么说session是下策因为session是有生命周期的如果不显式清理数据会在session里残留很久既占用内存又有信息泄露风险。用flash attribute的好处是读取之后立即移除不会污染session。6.3 坑三相对路径在转发与重定向中的混乱在一个前后端不分离的老项目中页面是通过转发渲染的页面里的资源引用全都是相对路径。系统上线后运维做了URL重写把某些长路径缩短了。结果转发渲染的页面里相对路径解析出来的地址全错了页面样式、图片全裂。排查过程很痛苦因为直接访问和内嵌转发看到的页面URL是一样的但服务器内部处理路径完全不同。后来把所有资源引用全部改成基于根路径的绝对路径这才消停。这个教训我记到现在写页面时引用资源永远不要依赖当前URL的层级关系。6.4 坑四302重定向导致POST请求变GET这个在前面提过但值得再强调一次。用一个真实场景用户提交订单时后端校验发现session过期于是response.sendRedirect(/login)。结果用户登录成功后还需要重新把订单数据再填一遍——因为原始POST数据在重定向时已经丢了第二次请求是GET没有任何表单数据。解决的思路通常是在重定向之前把订单临时数据存到session或者临时存储中登录成功后再读出来恢复上下文。这个方案实现起来不复杂但要意识到“重定向后POST变GET”这个约束才可能想到要额外做数据持久化。6.5 调试技巧用浏览器开发者工具验证一切写代码时别人怎么讲都不如自己亲眼看一遍。分享一个最实用的调试方法打开Chrome开发者工具切到Network面板勾选Preserve log然后触发一次页面跳转。如果看到的是“单个请求直接返回200没有第二次请求”说明是转发如果看到“连续两个请求第一个是302第二个是200且第二个请求地址是新URL”说明是重定向。这个观察方法能帮你快速确认当前用的到底是哪个机制。排查重定向死循环时也是看这个面板直接就能看到请求瀑布流在A和B之间来回跳。强烈建议所有后端开发都养成这个习惯。7. 高频面试问答速查把面试里最高频的几个问题整理成速查表方便你考前突击或工作间隙快速回顾。面试问题标准答案要点forward和redirect的区别请求次数不同、地址栏变化不同、能否跨域不同、参数传递方式不同、性能差异转发为什么地址栏不变转发是服务器内部行为浏览器只发一次请求不知道服务器内部做了资源切换重定向为什么地址栏会变服务器返回302和Location头浏览器重新发起新请求到新地址转发能跨域吗不能只能访问同一Web应用内的资源重定向能跨域吗可以不受域名限制转发时request里的数据能传到目标资源吗能因为整个过程中request对象未变重定向时request里的数据能传到目标资源吗不能第二次请求是全新的request对象表单提交后应该用转发还是重定向推荐重定向PRG模式防止刷新重复提交重定向默认是什么状态码302临时重定向301和302有什么区别301是永久重定向302是临时重定向301会被浏览器和搜索引擎永久缓存这几个问题回答清楚基本可以覆盖大部分后端面试里关于这个知识点的考察。但面试官如果继续追问“为什么表单重复提交要禁用转发”你要能把PRG模式的原理讲出来这就说明你是真懂了而不只是背答案。8. 最后的实操建议与个人体会做了这么多年后端我对forward和redirect最大的感受是它不是两个API而是两种Web协作的思维模式。在很多老项目中开发者习惯什么事都用转发导致URL长期不更新、页面刷新就重复提交、系统故障排查困难。而有的新项目则反过来把一切跳转都做成重定向导致请求量翻倍、数据传递只能靠URL参数代码里充满了各种手工拼接的参数和解析逻辑。两种极端都不好。懂原理不是让你“永远用这个不用那个”而是让你在合适的场景做出能让系统更稳定、更安全、更高效的选择。我个人在实际操作中的体会是先想清楚用户最终的地址栏应该显示什么再决定用那个机制。如果最终展示的页面就是用户要访问的页面用转发如果用户最终应该看到的是另一个URL用重定向。这个判断方式既简单又不会错比记忆一堆“什么场景该用什么”更实用。最后再分享一个小技巧如果你在用Spring Boot开发可以把所有重定向的URL统一配置在一个常量类里而不是散落各处魔法值。重定向URL一旦写错用户看到的是404或者跳到奇怪页面排查起来很消耗时间。集中管理之后至少能快速确认“这个跳转目标是不是拼错了”。正文就到这里。所有的原理、代码、坑点、面试题都覆盖到了建议你实际操作一遍用开发者工具亲眼看看那两次请求比背十遍理论都管用。
返回列表