在JSP里从一个页面跳到另一个页面,最直接的方式就两种:服务端转发和客户端重定向。很多人刚接触时容易搞混,写出来的代码跳转后地址栏没变,或者request里的数据莫名其妙丢了,基本都是没分清这两者的区别。
先看转发。假设你有个login.jsp,用户提交表单后想在同一个请求里跳到welcome.jsp,代码就这么写:
<% request.getRequestDispatcher("welcome.jsp").forward(request, response); %> 这行代码执行后,服务器内部把请求交给了welcome.jsp处理。浏览器地址栏还是login.jsp的URL,用户完全感觉不到页面换了。request里存的属性、参数都还在,welcome.jsp直接就能取。我第一次用的时候觉得挺神奇,后来看Servlet源码才明白,forward本质上就是服务器内部的一次方法调用,没经过浏览器。
但转发有个硬伤:它只能在同一个Web应用内跳。你想从自己的项目跳到百度,forward做不到。而且如果welcome.jsp已经往response里写了东西,再forward就会报IllegalStateException——响应已经提交了,没法再转。
重定向就不一样了。写法有两种,老派的是:
<% response.sendRedirect("welcome.jsp"); %> 这行代码干的事是:服务器告诉浏览器“你去访问welcome.jsp”,浏览器收到302状态码后重新发一个请求。地址栏会变成welcome.jsp的URL,用户能看到变化。代价是request里的数据全没了,因为这是两次独立的请求。想传数据?只能靠session或者URL参数。
我见过不少项目里用sendRedirect跳转后,下一个页面取不到request.setAttribute设的值,然后开发者在那儿debug半天。一问,果然是用错了跳转方式。
还有一种情况:JSP里写JavaScript跳转。比如:
<script> window.location.href = "welcome.jsp"; </script> 这其实跟JSP关系不大了,就是纯前端跳转。它的特点是页面会先加载完当前JSP的HTML,然后浏览器再执行JS跳走。用户可能会看到当前页面闪一下。适合那种需要先弹个提示再跳的场景,比如“登录成功,正在跳转...”。
实际项目里怎么选?我的习惯是:需要保留请求数据、且目标页面在同一应用内,用forward;需要改变URL、跳转到外部站点、或者防止用户刷新导致表单重复提交,用sendRedirect。表单提交后的跳转尤其推荐重定向,否则用户按F5会重复提交,这个坑我踩过不止一次。
还有个细节:forward之后,当前JSP里forward语句后面的代码不会再执行,因为请求已经被转走了。但sendRedirect后面的代码还会继续跑,除非你紧接着写return。有人写重定向后忘了return,结果后面的业务逻辑照常执行,数据库里多插了一条记录,查半天才发现问题。
另外,路径问题也容易出错。sendRedirect(“welcome.jsp”)是相对当前请求的URL,如果当前URL是/user/login.jsp,那实际跳的是/user/welcome.jsp。想跳根目录下的页面,得写request.getContextPath() + “/welcome.jsp”。forward的路径则是相对于Web应用的根,写“/welcome.jsp”就是从根开始找。
说白了,转发是服务器自己转,重定向是让浏览器再跑一趟。记住这个本质,用的时候就不会糊涂。