一直在搬代码,知道怎么写jsp,怎么写servlet,怎么运行tomcat,但是对这其中的请求过程往往就忽略了。相信大多数的初级程序员都是和我一样的,平时只知道搬代码而忽略了请求的过程问题。用了一个下午捋顺了一下,对tomcat的一个HTTP请求的过程。
首先,先说一下HTTP协议,HTTP协议也就是超文本传输协议,是一个关于如何在网络 上传输超级文本(HTML)的协议。在分层的计算机网络体系中HTTP位于应用层,建立在TCP/IP协议的基础上,HTTP靠的是可靠的TCP链接,默认的端口是80端口。HTTP协议规定web的基本运作过程基于客户/服务器通信模式。一个通信连接建立的过程如下:
1. 客户端与服务器端建立TCP连接。
2. 客户端发出HTTP请求。
3. 服务端返回响应的HTTP请求。
4. 客户端和服务器端的TCP连接关闭。
至于TCP连接是怎么建立的这里就不说了,好像是三次握手来着。用一个例子来说明,假设访问URL地址为http://www.inspur.com/news/index.htm的链接。具体的通信过程如下:
1. 浏览器与www.inspur.com服务器建立TCP连接。
2. 浏览器发出news/index.htm的HTTP请求。
3. web服务器在接收到请求之后解析HTTP请求返回包含index.htm数据的HTTP响应
4. 浏览器解析HTTP响应并显示
5. 浏览器与web服务器之间的TCP链接关闭。
这里需要说明的是在HTML文本中如果包含有图片,js,css等资源的时候,在浏览器解析HTML文件的时候会重新发起一个HTTP请求去请求图片资源。
接下来说一下HTTP请求的请求格式:
1.请求方法、URL和HTTP的协议版本。如:GET / HTTP/1.1
GET 完整请求一个资源,参数会显示在标题栏中。
POST:常用的提交表单方式,可以传输大量的数据。
HEAD:请求响应的首部。
DELETE:删除远程服务器上的文档。
PUT:上传文档到服务器。
2. 请求头。如:
Accept: / 就是告诉服务器端,我接受那些MIME类型
Accept-Language: zh-cn 告诉服务器能够发送哪些语言
Accept-Encoding: gzip, deflate 这个看起来是接受那些压缩方式的文件
User-Agent: Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 2.0.50727; .NET CLR 3.0.04506.648; .NET CLR 3.5.21022) 用户代理,一般情况是浏览器
Host: www.google.cn 用来标识请求服务器上的那个虚拟主机
Connection: Keep-Alive
3. 请求正文,请求正文和请求头之间需要用空行分隔。请求体中可以包含大量信息。
HTTP响应的响应格式
1. HTTP协议的版本、状态吗、描述。如:HTTP/1.1 200 OK 三者之间用空格分隔。
2. 响应头。包含服务器类型、正文类型、正文长度等信息。如
Date: Fri, 22 May 2009 06:07:21 GMT
Content-Type: text/html; charset=UTF-8
3. 响应正文。响应正文就是服务器返回的具体信息。通常是HTML文档。
什么事MIME类型?
MIME(Multipurpose Internet Mail Extesions 多用途互联网邮件扩展)是一个互联网标准。在请求和响应中的文件(数据)类型,通常都是通过MIME类型进行指定的。在请求和响应中都有一个ContentType项指定请求或者响应正文部分的MIME类型。如:上传文档时的request请求的MIME类型为multipart/form-data,而在表单提交时的MIME类型则是默认的application/x-www-form-urlencoded 服务器端会根据不同的MIME类型进行不同的处理。同时在响应端也是如此。会根据正文的不同类型做出不同为响应。
在分析过一个HTTP请求之后,我们来看一下通常服务器端的响应,我们拿Tomcat和JSP来进行举例说明,在web的发展过程中,我们经历了从静态页面到动态页面的发展历程。
所谓静态文档就是事先存放在web服务器中的html文档,当请求web服务器时,服务器找到此文档并且返回该文档。这个阶段的HTML文件只能包含文本以及图片。
动态文档,就是在请求之前并不存在而是在请求过程中动态生成的响应。这一阶段用到了CGI程序和Servlet程序。
静态文档就没什么好说的了,主要说一下动态的响应的产生和发送。
如果想知道动态的响应产生,那么就要先说一下web容器,这里我们简单的说一下tomcat容器。
先说一下tomcat的简单构成,用个tomcat的程序狗应该都知道tomcat有一个server.xml里面配置了一些标签。
Server:代表了整个容器
Service: 是这样一个集合:它由一个或者多个Connector组成,以及一个Engine,负责处理所有Connector所获得的客户请求.
Connector:
一个Connector将在某个指定端口上侦听客户请求,并将获得的请求交给Engine来处理,从Engine处获得回应并返回客户
TOMCAT有两个典型的Connector,一个直接侦听来自browser的http请求,一个侦听来自其它WebServer的请求
Coyote Http/1.1 Connector 在端口8080处侦听来自客户browser的http请求
Coyote JK2 Connector 在端口8009处侦听来自其它WebServer(Apache)的servlet/jsp代理请求
Engine:Engine下可以配置多个虚拟主机Virtual Host,每个虚拟主机都有一个域名
当Engine获得一个请求时,它把该请求匹配到某个Host上,然后把该请求交给该Host来处理
Engine有一个默认虚拟主机,当请求无法匹配到任何一个Host上的时候,将交给该默认Host来处理
Host:代表一个Virtual Host,虚拟主机,每个虚拟主机和某个网络域名Domain Name相匹配每个虚拟主机下都可以部署(deploy)一个或者多个Web App,每个Web App对应于一个Context,有一个Context path当Host获得一个请求时,将把该请求匹配到某个Context上,然后把该请求交给该Context来处理匹配的方法是“最长匹配”,所以一个path==”“的Context将成为该Host的默认Context所有无法和其它Context的路径名匹配的请求都将最终和该默认Context匹配。
Context:
一个Context对应于一个Web Application,一个Web Application由一个或者多个Servlet组成
Context在创建的时候将根据配置文件
CATALINAHOME/conf/web.xml和
WEBAPP_HOME/WEB-INF/web.xml载入Servlet类,当Context获得请求时,将在自己的映射表(mapping table)中寻找相匹配的Servlet类.如果找到,则执行该类,获得请求的回应,并返回。
下面是tomcat的响应图示:
需要说明的是一个Context对应一个web app 。一个项目中可能包含多个servlet。
当一个Web App被初始化的时候,它将用自己的ClassLoader对象载入“部署配置文件web.xml”中定义的每个servlet类
它首先载入在$CATALINA_HOME/conf/web.xml中部署的servlet类
然后载入在自己的Web App根目录下的WEB-INF/web.xml中部署的servlet类
web.xml文件有两部分:servlet类定义和servlet映射定义
每个被载入的servlet类都有一个名字,且被填入该Context的映射表(mapping table)中,和某种URL PATTERN对应
当该Context获得请求时,将查询mapping table,找到被请求的servlet,并执行以获得请求回应
分析一下所有的Context共享的web.xml文件,在其中定义的servlet被所有的Web App载入。
下面举一个例子来简要说明一下这一过程:
假设来自客户的请求为:
http://localhost:8080/inspur/index.jsp
请求被发送到本机端口8080,被在那里侦听的Coyote HTTP/1.1 Connector获得
Connector把该请求交给它所在的Service的Engine来处理,并等待来自Engine的回应
Engine获得请求localhost/inspur/index.jsp,匹配它所拥有的所有虚拟主机Host
Engine匹配到名为localhost的Host(即使匹配不到也把请求交给该Host处理,因为该Host被定义为该Engine的默认主机)
localhost Host获得请求/inspur/index.jsp,匹配它所拥有的所有Context
Host匹配到路径为/inspur的Context(如果匹配不到就把该请求交给路径名为”“的Context去处理)
path=”/inspur”的Context获得请求/index.jsp,在它的mapping table中寻找对应的servlet
Context匹配到URL PATTERN为*.jsp的servlet,对应于JspServlet类
构造HttpServletRequest对象和HttpServletResponse对象,作为参数调用JspServlet的doGet或doPost方法
Context把执行完了之后的HttpServletResponse对象返回给Host
Host把HttpServletResponse对象返回给Engine
Engine把HttpServletResponse对象返回给Connector
Connector把HttpServletResponse对象返回给客户browser
这里可能有一个疑问,如果没有请求的servlet mapping会怎么样?其实请求jsp文件和servlet文件是一样的。在请求道jsp时,jsp会简单的处理此文件,把此文件转化为.java文件,其实很简单,原本的HTML内容转化为out.println(),而jsp中内嵌的java程序原封不动的保留,然后经过servlet容器进行编译,编译成servlet类,这样在执行完servlet类之后会返回响应对象,这样就和上面的过程相一致了。通常servlet类只会加载一次,因为一般的servlet的运行模式都是单例多线程运行。(虽然节省了内存,提高了响应时间。但这样会导致一些安全性的问题)。关于servlet的安全性问题以后有时间再深入学习一下。简单的HTTP请求过程我理解的大概就是这样,以后计划深入学习一下tomcat的一些内置对象,上面总结的如果有错误的地方还请批评改正,希望我们能一同进步。
特别感谢两篇博客: http://www.cnblogs.com/fireman/archive/2012/12/05/2804138.html
http://blog.csdn.net/yipiankongbai/article/details/25029183