在Java Web开发中有两个极为重要的概念,一个叫转发,一个叫重定向。其中转发是Java Web中特有的概念,而重定向是HTTP协议中的规定,所有的后端语言都有对应的实现,如PHP、Python等。
下面我们详细讲解这两种技术的不同。
转发是Java Web应用程序内部做的事情,与浏览器无关。详见下图,当浏览器发送一个请求1到服务器,a.jsp处理完毕后,转发到b.jsp中处理。可以理解成HTTP的请求还未结束,所以a.jsp和b.jsp中共享一个request对象。
开发
代码实践,在testWeb01项目下,新建一个dingxiang文件夹,里面新建a.jsp和b.jsp,如下图所示:
a.jsp代码:
<%@ page language="java" contentType="text/html; charset=utf-8" pageEncoding="utf-8"%> <!DOCTYPE> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=utf-8"> <title>a页面</title> </head> <body> <div>a页面</div> <% //在request作用域中添加一个名为name,值为Tom的属性 request.setAttribute("name", "Tom"); //转发到b.jsp页面 request.getRequestDispatcher("b.jsp").forward(request, response); %> </body> </html>
b.jsp代码:
<%@ page language="java" contentType="text/html; charset=utf-8" pageEncoding="utf-8"%> <!DOCTYPE> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=utf-8"> <title>b页面</title> </head> <body> <div>b页面</div> <% //从作用域中,拿到name属性的值,并输出在页面上 out.print(request.getAttribute("name")); %> </body> </html>
测试:
在浏览器中输入localhost:8080/testWeb01/dingxiang/a.jsp,访问a.jsp,会出现如下图页面,说明转发到了b.jsp,而且正确的输出了Tom,说明在b.jsp中获取request中的name属性值,是成功的。
注意观察浏览器的地址栏,仍然是显示的是a.jsp,这是因为对于浏览器而言,它并不知道服务器内部做了a文件与b文件的处理。
总结:
转发纯粹是服务器内部做的事情,浏览器并不知晓,转发被认为是同一个request,所以共享同一个request对象。在实际应用中,往往是服务器内部需要多个文件合作处理完成一个请求的功能时,会用到转发。另外,在现代行业规范下,转发会被广泛应用在后续我们会讲到的MVC模式开发中由Servlet转到JSP页面这一情景中。
重定向是HTTP协议的一项标准,是由浏览器和服务器共同实现的。
通过下图,我们来看,当浏览器发送一个对a.jsp的请求时(请求1),a.jsp处理完毕,响应(响应1)给浏览器,在报头中指定status的值是302(该状态码在HTTP协议中表示重新定向),指定location的值是b.jsp,那当浏览器接收到响应1的302和b.jsp后,会自动发起一次新的请求(请求2),访问b.jsp。
因为请求2是自动发起的,所以对用户来说可能不会切实感知,但它是经由两次网络请求,所以对于浏览器的地址栏也会及时变化为b.jsp。
开发
在刚才文件中定义连个页面:c.jsp、d.jsp。
c.jsp代码:
<%@ page language="java" contentType="text/html; charset=utf-8" pageEncoding="utf-8"%> <!DOCTYPE> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=utf-8"> <title>c页面</title> </head> <body> <div>c页面</div> <% //在request作用域中添加一个名为name,值为Tom的属性 request.setAttribute("name", "Tom"); //重定向到d.jsp页面 response.sendRedirect("d.jsp"); %> <% //out.println("c执行完毕"); //System.out.println("c执行完毕"); %> </body> </html>
d.jsp代码:
<%@ page language="java" contentType="text/html; charset=utf-8" pageEncoding="utf-8"%> <!DOCTYPE> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=utf-8"> <title>d页面</title> </head> <body> <div>d页面</div> <% //从作用域中,拿到name属性的值,并输出在页面上 out.print(request.getAttribute("name")); %> <% //out.println("d执行完毕"); //System.out.println("d执行完毕"); %> </body> </html>
效果如图所示,因为重定向后所发起的请求是浏览器发起的一次新的请求,所以地址栏的地址产生变化。而正是因为这是一次新的请求,所以不会和上一次请求共享一个request对象。时期请求1的生命周期已经在发起响应1的时候已经结束了。所以request作用域中并不存在名为name的属性,所以显示为null。
总结:
重定向是HTTP协议的一项规范,需要浏览器和服务器技术同时实现。可以通过浏览器的控制台的“网络”选项卡(见下图)看到它是发送了两次请求,其中对c.jsp访问,响应回status等于302,location等于d.jsp。在实际开发中,通常用于一次请求下,某个功能模块已经执行完毕,要重新定向到另一个功能模块。