页面跳转的两种方式(转发和重定向)区别详解:

作为一名程序员,特别是java web开发的程序员,在使用servlet/jsp的时候,我们必须要知道实现页面跳转的两种方式的区别和联系:即转发和重定向的区别。


      1、RequestDispatcher.forward方法只能将请求转发给同一个WEB应用中的组件;而HttpServletResponse.sendRedirect 方法不仅可以重定向到当前应用程序中的其他资源,还可以重定向到同一个站点上的其他应用程序中的资源,甚至是使用绝对URL重定向到其他站点的资源。如果传递给HttpServletResponse.sendRedirect 方法的相对URL以“/”开头,它是相对于整个WEB站点的根目录;如果创建RequestDispatcher对象时指定的相对URL以“/”开头,它是相对于当前WEB应用程序的根目录。


      2、调用HttpServletResponse.sendRedirect方法重定向的访问过程结束后,浏览器地址栏中显示的URL会发生改变,由初始的URL地址变成重定向的目标URL;而调用RequestDispatcher.forward 方法的请求转发过程结束后,浏览器地址栏保持初始的URL地址不变。


      3、HttpServletResponse.sendRedirect方法对浏览器的请求直接作出响应,响应的结果就是告诉浏览器去重新发出对另外一个URL的 访问请求,这个过程好比有个绰号叫“浏览器”的人写信找张三借钱,张三回信说没有钱,让“浏览器”去找李四借,并将李四现在的通信地址告诉给了“浏览器”。于是,“浏览器”又按张三提供通信地址给李四写信借钱,李四收到信后就把钱汇给了“浏览器”。可见,“浏览器”一共发出了两封信和收到了两次回复, “浏览器”也知道他借到的钱出自李四之手。RequestDispatcher.forward方法在服务器端内部将请求转发给另外一个资源,浏览器只知道发出了请求并得到了响应结果,并不知道在服务器程序内部发生了转发行为。这个过程好比绰号叫“浏览器”的人写信找张三借钱,张三没有钱,于是张三找李四借了一些钱,甚至还可以加上自己的一些钱,然后再将这些钱汇给了“浏览器”。可见,“浏览器”只发 出了一封信和收到了一次回复,他只知道从张三那里借到了钱,并不知道有一部分钱出自李四之手。


       4、RequestDispatcher.forward方法的调用者与被调用者之间共享相同的request对象和response对象,它们属于同一个访问请求和响应过程;而HttpServletResponse.sendRedirect方法调用者与被调用者使用各自的request对象和response对象,它们属于两个独立的访问请求和响应过程。对于同一个WEB应用程序的内部资源之间的跳转,特别是跳转之前要对请求进行一些前期预处理,并要使用HttpServletRequest.setAttribute方法传递预处理结果,那就应该使用RequestDispatcher.forward方法。不同WEB应用程序之间的重定向,特别是要重定向到另外一个WEB站点上的资源的情况,都应该使用HttpServletResponse.sendRedirect方法。


        5、无论是RequestDispatcher.forward方法,还是HttpServletResponse.sendRedirect方法,在调用它们之前,都不能有内容已经被实际输出到了客户端。如果缓冲区中已经有了一些内容,这些内容将被从缓冲区中。


以上五点的论述来源于: 点击查看原文论述


一、转发和重定向的图解


 

java转发请求时转发请求IP_request



1)请求转发:
  request.getRequestDispatcher(URL地址).forward(request, response)


处理流程:


  • 客户端发送请求,Servlet做出业务逻辑处理。
  • Servlet调用forword()方法,服务器Servlet把目标资源返回给客户端浏览器。

 

java转发请求时转发请求IP_服务器_02

 

2)重定向:
  response.sendRedirect(URL地址)


处理流程:


  • 客户端发送请求,Servlet做出业务逻辑处理。
  • Servlet调用response.sendReadirect()方法,把要访问的目标资源作为response响应头信息发给客户端浏览器。
  • 客户端浏览器重新访问服务器资源xxx.jsp,服务器再次对客户端浏览器做出响应。

 

java转发请求时转发请求IP_重定向_03

 

  以上两种情况,你都需要考虑Servlet处理完后,数据如何在jsp页面上呈现。图例是请求、响应的流程,没有标明数据如何处理、展现。


二、两种跳转获得对象的方式


[AppleScript]  纯文本查看  复制代码




?






三、转发和重定向的路径问题

1)使用相对路径在重定向和转发中没有区别
2)重定向和请求转发使用绝对路径时,根/路径代表了不同含义
重定向response.sendRedirect("xxx")是服务器向客户端发送一个请求头信息,由客户端再请求一次服务器。/指的Tomcat的根目录,写绝对路径应该写成"/当前Web程序根名称/资源名" 。如"/WebModule/login.jsp","/bbs/servlet/LoginServlet"
转发是在服务器内部进行的,写绝对路径/开头指的是当前的Web应用程序。绝对路径写法就是"/login.jsp"或"/servlet/LoginServlet"。


总结:以上要注意是区分是从服务器外的请求,还在是内部转发,从服务器外的请求,从Tomcat根写起(就是要包括当前Web的根);是服务器内部的转发,很简单了,因为在当前服务器内,/写起指的就是当前Web的根目录。

四、转发和重定向的区别

  • request.getRequestDispatcher()是容器中控制权的转向,在客户端浏览器地址栏中不会显示出转向后的地址;服务器内部转发,整个过程处于同一个请求当中。
    response.sendRedirect()则是完全的跳转,浏览器将会得到跳转的地址,并重新发送请求链接。这样,从浏览器的地址栏中可以看到跳转后的链接地址。不在同一个请求。重定向,实际上客户端会向服务器端发送两个请求。
    所以转发中数据的存取可以用request作用域:request.setAttribute(), request.getAttribute(),重定向是取不到request中的数据的。只能用session。
  • forward()更加高效,在可以满足需要时,尽量使用RequestDispatcher.forward()方法。(思考一下为什么?)
  • RequestDispatcher是通过调用HttpServletRequest对象的getRequestDispatcher()方法得到的,是属于请求对象的方法。
    sendRedirect()是HttpServletResponse对象的方法,即响应对象的方法,既然调用了响应对象的方法,那就表明整个请求过程已经结束了,服务器开始向客户端返回执行的结果。
  • 重定向可以跨域访问,而转发是在web服务器内部进行的,不能跨域访问。

五、转发和跳转的小结     

      1、转发使用的是getRequestDispatcher()方法;重定向使用的是sendRedirect();


      2、转发:浏览器URL的地址栏不变。重定向:浏览器URL的地址栏改变;


      3、转发是服务器行为,重定向是客户端行为;


      4、转发是浏览器只做了一次访问请求。重定向是浏览器做了至少两次的访问请求;


      5、转发2次跳转之间传输的信息不会丢失,重定向2次跳转之间传输的信息会丢失(request范围)。

六、转发和重定向的选择     

      1、重定向的速度比转发慢,因为浏览器还得发出一个新的请求,如果在使用转发和重定向都无所谓的时候建议使用转发。


      2、因为转发只能访问当前WEB的应用程序,所以不同WEB应用程序之间的访问,特别是要访问到另外一个WEB站点上的资源的情况,这个时候就只能使用重定向了。

七、转发和重定向的应用场景     

  在上面我已经提到了,转发是要比重定向快,因为重定向需要经过客户端,而转发没有。有时候,采用重定向会更好,若需要重定向到另外一个外部网站,则无法使用转发。另外,重定向还有一个应用场景:避免在用户重新加载页面时两次调用相同的动作。


       例如,当提交产品表单的时候,执行保存的方法将会被调用,并执行相应的动作;这在一个真实的应用程序中,很有可能将表单中的所有产品信息加入到数据库中。但是如果在提交表单后,重新加载页面,执行保存的方法就很有可能再次被调用。同样的产品信息就将可能再次被添加,为了避免这种情况,提交表单后,你可以将用户重定向到一个不同的页面,这样的话,这个网页任意重新加载都没有副作用;


       但是,使用重定向不太方便的地方是,使用它无法将值轻松地传递给目标页面。而采用转发,则可以简单地将属性添加到Model,使得目标视图可以轻松访问。由于重定向经过客户端,所以Model中的一切都会在重定向时丢失。但幸运的是,在Spring3.1版本以后,我们可以通过Flash属性,解决重定向时传值丢失的问题。


       要使用Flash属性,必须在Spring MVC的配置文件中添加一个<annotation-driven/>。然后,还必须再方法上添加一个新的参数类型:org.springframework.web.servlet.mvc.support.RedirectAttributes。


如下所示:



[AppleScript]  纯文本查看  复制代码




?
               1                   2                   3                   4                   5                   6                     /                     /                     获得转发对象getRequestDispatcher                     (                     )                                                             HttpServletRequest                     (                     httpServletRequest                     )                     .getRequestDispatcher                                                             ServletContext.getRequestDispatcher                     (                     )                     ;                                                                                                                           /                     /                     获得重定向对象sendRedirect                     (                     )                                                             HttpServletResponse                     (                     httpServletResponse                     )                     .sendRedirect                     (                     )                     ;