请求转发和请求包含

简介: 1、Servlet 容器   编程中的容器我们可以理解为程序运行时需要的环境,那么Tomcat 就是Servlet 的运行环境,就是一个Servlet 容器。Servlet 容器的作用是负责处理客户请求,当Servlet 容器获取到用户请求后,调用某个Servlet,并把Servlet 的执行结果返回给用户。    Servlet 容器的工作流程:   ● 当用户请求

1、Servlet 容器



  编程中的容器我们可以理解为程序运行时需要的环境,那么Tomcat 就是Servlet 的运行环境,就是一个Servlet 容器。Servlet 容器的作用是负责处理客户请求,当Servlet 容器获取到用户请求后,调用某个Servlet,并把Servlet 的执行结果返回给用户。 


  Servlet 容器的工作流程:


   当用户请求某个资源时,Servlet 容器使用ServletRequest 对象将用户的请求信息封装起来,然后调用 java Servlet API 中定义的Servlet 的生命周期方法,完成Servlet 的运行。

   Servlet 容器将Servlet 执行后需要返回用户的结果封装到 ServletResponse 对象中,最后由Servlet 容器发送给客户,完成对客户的一次服务过程。

   每一个Servlet 都会执行 init()、service()、destory() 三个方法,在启动时调用一次init) 方法对参数进行初始化,在该Servlet 生存期间每当收到对其的请求时都会调用Service() 方法对请求进行处理,当容器销毁时自动调用 destory() 方法对Servlet 进行销毁。 


2、请求转发和请求包含


  正是因为因为Servlet 中的service() 方法由Servlet 容器调用,所以一个 Servlet 的对象是无法调用另一个 Servlet 的方法的,但是在实际项目中,对于客户端请求做出的响应可能会复杂,需要多个Servlet 来协作完成,这就需要请求转发和请求包含技术了。但是,要注意,无论是请求转发还是请求包含,都是表示由多个Servlet 共同处理同一个请求


(1)请求转发定义:


  Servlet(源组件)先对客户请求做一些预处理操作(一般是对响应头进行处理),然后把请求转发给其他Servlet(目标组件)来完成包括生成响应结果在内的后续操作。

  实现方法:request.getRequestDispatcher(“接收请求的Servlet 路径”). forward(request,response)

  getRequestDispatcher(String path):该方法的返回值类型是RequestDispatcher,请求发送器,该方法的参数是指明要接收请求的Servlet 的路径;

  forward(ServletRequest req,ServletResponse res):该方法是RequestDispatcher 接口的方法,将请求从一个 servlet 转发到服务器上的另一个资源(servlet、JSP 文件或 HTML 文件)。此方法允许一个 servlet 对请求进行初步处理,并使另一个资源生成响应。需要传递两个参数,这两个参数是当前Servlet 的request 对象和 response 对象传递过去的。


  forward() 方法的处理流程:


  ● 清空用于存放响应正文(响应体)数据的缓冲区。

  ● 如果目标组件为Servlet 或JSP,就调用它们的service() 方法,把该方法产生的响应结果发送到客户端,如果目标组件为文件系统中的静态 html 文档,就读去文档中的数据并把它发送到客户端。

  ● 由于 forward() 方法先清空用于存放响应正文数据的缓冲区,因此servlet源组件生成的响应结果不会被发送到客户端,只有目标组件生成的结果才会被发送到客户端,所以对源组件叫“留头不留体”,目标组件为“留体不留头”。

  ● 如果源组件在进行请求转发之前,已经提交了响应结果(例如调用了flush 或close() 方法),那么forward() 方法会抛出IllegalStateException。为了避免该异常,不应该在源组件中提交响应结果,所以叫留体抛异常。


(2)请求包含定义:


  Servlet(源组件)把其他Servlet(目标组件)生成的响应结果包含到自身的响应结果中。

  实现方式:request.getRequestDispatcher(“接收请求的Servlet 路径”). include(request,response)

  include(ServletRequest request,ServletResponse response):该方法是RequestDispatcher 接口的方法,表示包含。它的参数同forward() 方法的参数一样都是由当前Servlet传递过去的。

  包含与转发相比,源组件与被包含的目标组件的输出数据都会被添加到响应结果中,在目标组件中对响应状态代码或者响应头所做的修改都会被忽略,所以对源组件来说是“留头又留体”,对目标组件为“留体不留头”。

  注意:当Servlet 源组件调用 RequestDispatcher 的 forward 或 include 方法时,都要把当前的 ServletRequest 对象和ServletResponse 对象作为参数传给 forward 或 include 方法,这就使得源组件和目标组件共享同一个ServletRequest 对象和ServletResponse 对象,就实现了多个Servlet 协同处理同一个请求。


附:RequestDispatcher 接口


  RequestDispatcher 接口中定义了两个方法::forward() 方法和 include() 方法,它们分别用于将请求转发到 RequestDispatcher 对象封装的资源和将 RequestDispatcher 对象封装的资源作为当前响应内容的一部分包含进来.


3、请求转发(留头不留体,留体抛异常)


  AServlet(发送请求方):

package web.servlet;
import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

public class AServlet extends HttpServlet {

	public void doGet(HttpServletRequest request, HttpServletResponse response)throws ServletException, IOException {
		
		response.setContentType("text/html;charset=utf-8"); 
		response.getWriter().print("您好!");
		//response.getWriter().flush();//刷新会导致response的状态为已提交!
		
		// 转发不能在response提交之后,否则就会抛异常
		request.getRequestDispatcher("/BServlet").forward(request, response);
	}
}

  BServlet(接收请求方):

package web.servlet;
import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

public class BServlet extends HttpServlet {
	public void doGet(HttpServletRequest request, HttpServletResponse response)throws ServletException, IOException {		
		response.getWriter().print("我很棒!");
	}
}

  运行结果为:“我很棒!”(不会输出“你好!”)。


  我对留头不留体的分析:


    对于发出请求的Aservlet是:留头不留体(设置的响应头可以留下,响应体被接收请求的 Bservlet 响应体覆盖); 留体抛异常,就是说只要请求转发了,就要将请求完全由 Bservlet 处理,Aservlet就不能插手了,如果Aservlet 也提交了对请求的处理,那么Bservlet 就不能处理请求了(因为请求已经被Aservlet 处理了,还处理啥) ,你安排人家处理请求,最终却由你处理了,当forward() 转发请求时,发现请求已经被处理,就会抛出异常。

    不过要注意,只有当AServlet 提交了处理(如例中手动flush将缓冲区内数据提交)才会抛出异常,如果没有提交,说明之前A对请求的处理还在缓冲区中,B就会直接将A的缓冲区清空,然后覆盖掉,就形成了之前的留头不留体。


4、请求包含(留头又留体)


  CServlet(发送请求方):

package web.servlet;
import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

/**
 * 请求包含:留头又留体
 */
public class CServlet extends HttpServlet {

	public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		
		response.setContentType("text/html;charset=utf-8"); //设置内容类型
		response.getWriter().print("你好!");
		request.getRequestDispatcher("/DServlet").include(request, response);
	}
}

  DServlet(接收请求方):

package web.servlet;
import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

public class DServlet extends HttpServlet {
	public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {		
		response.getWriter().print("我很棒!");
	}
}

  运行结果为:你好!我很棒!

  结果说明请求包含是多个Servlet 共同处理一个请求的,并且发送方和接收方都能够留下响应体。


5、请求转发和请求包含的比较


  (1)相同点:


    请求转发和请求包含都是在处理一个相同的请求,多个Servlet之间使用同一个 request 对象和 response 对象。


  (2)不同点:


    ● 如果在AServlet中请求转发到BServlet,那么在AServlet中不允许再输出响应体,即不能使用response.getWriter() 和response.getOutputStream() 向客户端输出,这一工作交由BServlet来完成;如果是由AServlet请求包含BServlet,则没有这个限制。

    ● 请求转发不能设置响应体,但是可以设置响应头,简单来说就是“留头不留体”,例如:response.setContentType("text/html;charset=utf-8”) 是可以留下来的;请求包含不仅可以设置响应头,还可以设置响应体,简单来说就是“留头又留体“。

    ● 请求转发大多应用在Servlet中,转发目标大多是jsp页面;请求包含大多应用在jsp页面中,完成多页面的合并。一般情况下经常使用的是请求转发。


6、请求转发的应用:


  ● 在Servlet中向数据库获取数据,保存到request域中;

  ● 转发到jsp页面,jsp从request域中获取数据,显示在页面上。


7、请求转发和重定向的区别


  ● 对于客户端浏览器来说,转发是一个请求,重定向是两个请求;

  ● 转发浏览器地址栏不变化,重定向会变成转发后的URL ;

  ● 转发只能在一个项目内,而重定向没有限制,可以重定向到任意网址,如京东、淘宝等 ;

  ● 转发可以使用request 域传递数据,而重定向不能。因为转发是一个请求,重定向是两个请求;

  ● 转发只有一个请求,原来是什么请求方式就是什么方式;而重定向两个请求,第一个可能为post 可能为get ,但是第二个请求一定是get 。


  小结:在浏览器地址栏中输入某个URL地址或单击网页上的一个超链接时,浏览器发出的HTTP请求消息的请求方式为GET。如果网页中的<form>表单元素的method属性被设置为“GET”,浏览器提交这个FORM表单时生成的HTTP请求消息的请求方式也为GET



目录
相关文章
|
6月前
|
存储 缓存
ETag的值是如何在HTTP响应中传递给客户端的
ETag的值是如何在HTTP响应中传递给客户端的
|
小程序
小程序接口请求配置
小程序接口请求配置
173 0
|
6月前
|
前端开发
请求转发和重定向的区别
请求转发和重定向的区别
89 0
|
6月前
|
JSON 前端开发 JavaScript
关于我认识的请求方式
关于我认识的请求方式有三个
68 0
|
6月前
|
存储 数据处理
Request请求转发与Respones请求重定向有什么区别?
Request请求转发与Respones请求重定向有什么区别?
重定向和请求转发的区别
重定向和请求转发的区别
95 0
HttpServletRequest共享数据、请求转发、请求包含、获取流对象及中文乱码问题
HttpServletRequest共享数据、请求转发、请求包含、获取流对象及中文乱码问题
90 0
|
缓存 算法
HTTP协议中的ETag头字段如何实现快速判断资源是否变化?
HTTP协议中的ETag头字段如何实现快速判断资源是否变化?
189 0
|
前端开发
请求转发与请求重定向
请求转发与请求重定向
272 0
请求转发与请求重定向