1.概述
Web的应用层协议即为HTTP协议(HyperText Transfer Protocol,超文本传输协议),HTTP协议是Web应用的核心。它由两个程序实现:一个客户程序和一个服务器程序(即Web浏览器和Web服务器)。客户程序和服务器程序运行在不同的端系统中,通过交换HTTP报文进行会话。HTTP定义这些报文的结构以及客户和服务器进行报文交换的方式。
HTTP使用TCP作为它的支撑运输协议,因为TCP是可靠的,它可以为HTTP提供可靠的数据传输。HTTP客户端首先发起一个与服务器的TCP连接,一旦连接建立,该浏览器和服务器进程就可以通过套接字访问TCP。客户向它的套接字接口发送HTTP请求报文并从它的套接字接口接收HTTP响应报文。
服务器向客户发送被请求的对象,而不存储任何关于该客户的状态信息。假如某个特定客户在短短的几秒钟内两次请求同一个对象,服务器并不会因为刚刚为客户提供了该对象就不再作出响应,而是会重新发送该对象。也就是说HTTP是一个无状态协议
2.非持续连接和持续连接
我们在访问一个网站的时候,一般要停留很久。也就是说我们的客户浏览器与服务器要在相当长的时间内持续通信,其中客户发出一系列请求并且服务器对每个请求进行响应。这样我们就需要确定每个请求/响应对是经过一个单独的TCP连接发送,还是所有的请求及其响应都由一个相同的TCP连接发送。前者就是非持续连接,后者就是持续连接。
在HTTP/1.0版本中,HTTP协议默认是非持续连接,也就是每个TCP连接只能发送一个请求,发送数据完毕后,连接就关闭,如果还要请求其他资源,就必须再创建一个连接。对于每一个连接,在客户和服务器中都要分配TCP的缓冲区和保持TCP变量,这给Web服务器带来了严重的负担。
在HTTP/1.1版本中,通过在HTTP请求头中添加了Connection: Keep-Alive
字段,来使双方维持连接。当服务器收到附带有Connection: Keep-Alive
的请求时,它也会在响应头中添加一个同样的字段来使用Keep-Alive
。这样一来,客户端和服务器之间的HTTP连接就会被保持,不会断开,当客户端发送另外一个请求时,就使用这条已经建立的连接。
客户端和服务器发现对方一段时间没有活动,就可以主动关闭连接。不过,规范的做法是,客户端在最后一个请求时,发送Connection: close
,明确要求服务器关闭TCP连接。
另外,HTTP/1.1版本支持流水线式的持续请求,也就是说,客户端可以一个一个地发出请求,而不必等待对未决请求的回答。
HTTP的默认模式是使用带流水线的持续连接!
但是需要注意的是:
1.HTTP是一个无状态协议,这意味着每个请求都是独立的,Keep-Alive没能改变这个结果。另外,Keep-Alive也不能保证客户端和服务器之间的连接一定是活跃的,在HTTP1.1版本中也如此。唯一能保证的就是当连接被关闭时你能得到一个通知,所以不应该让程序依赖于Keep-Alive的保持连接特性,否则会有意想不到的后果。
2.使用长连接之后,客户端、服务端怎么知道本次传输结束呢?两部分:(1) 判断传输数据是否达到了Content-Length 指示的大小;(2) 动态生成的文件没有 Content-Length ,它是分块传输(chunked),这时候就要根据 chunked 编码来判断,chunked 编码的数据在最后有一个空 chunked 块,表明本次传输数据结束
3.HTTP报文
HTTP报文是面向文本的,报文中的每一个字段都是一些ASCII码串,各个字段的长度是不确定的。HTTP报文有两种:HTTP请求报文和HTTP响应报文
3.1 HTTP请求报文
下图即为HTTP请求报文的通用格式。
【1】HTTP请求报文的第一行叫做请求行,其后继的行叫做首部行,也可以叫作请求头。
【2】请求行有3个字段:方法字段、URL字段和HTTP版本字段。方法字段可以取几种不同的值,包括GET、POST、HEAD、PUT和DELETE。其中GET和POST最为常用。
【3】请求头部为请求报文添加了一些附加信息,由“名/值”对组成,每行一对,名和值之间使用冒号分隔。常见请求头如下:
请求头 | 说明 |
---|---|
Host | 接受请求的服务器地址,可以是IP:端口号,也可以是域名 |
User-Agent | 发送请求的应用程序名称 |
Connection | 指定与连接相关的属性,如Connection:Keep-Alive |
Accept-Charset | 通知服务端可以发送的编码格式 |
Accept-Encoding | 通知服务端可以发送的数据压缩格式 |
Accept-Language | 通知服务端可以发送的语言 |
If-Modified-Since | 用于告诉服务器,客户机对于资源的最后缓存时间 |
Referer | 告诉服务器,客户机是从哪个页面去访问服务器的 (防盗链) |
Cookie | 向服务器传递Cookie |
请求头部的最后会有一个空行,表示请求头结束,这一行必不可少。接下来为请求数据。
【4】请求数据也叫作实体体或者请求体,使用GET方法时请求体为空,而使用POST方法时才使用该请求体。当用户提交表单时,HTTP客户端常常使用POST方法,例如,当用户登录某个网站的时候,需要向服务器提供用户名和密码。这时候,请求体中包含的就是用户在表单字段中的输入值。
下图是实际请求百度的时候的HTTP请求报文。
【注】GET和POST都可以用于向服务器提交表单,提交数据。有关GET方法和POST的异同可以参考:
【 Servlet——通过GenericServlet和HttpServlet开发Servlet】一文的最后。
3.2 HTTP响应报文
HTTP响应报文的通用格式是这样的:
【1】HTTP响应报文格式与请求报文格式基本是一样的
【2】响应报文的第一行为状态行,状态行包括3个字段:协议版本字段,状态码和相应状态信息。一些常用的状态码和相关的短语包括:
状态码 | 相应的短语 | 说明 |
---|---|---|
200 | OK | 请求成功,信息在返回的响应报文中 |
301 | Moved Permanently | 请求的对象已经被永久转移了,新的URL定义在响应报文的Location:首部行中。客户软件将自动获取新的URL |
400 | Bad Request | 一个通用的差错代码,指示该请求不能被服务器理解 |
404 | Not Found | 被请求的文档不在服务器上 |
505 | HTTP Version Not Supported | 服务区不支持请求报文使用的HTTP协议版本 |
【3】响应头部与请求头部类似,它为响应报文添加了一些附加信息,一些常见的响应头如下:
响应头 | 说明 |
---|---|
Location | 这个头通常配合302或301状态码使用,服务器使用这个头告诉浏览器去找谁 |
Server | 服务器通过这个头告诉浏览器,服务器的类型 |
Content-Encoding | 告诉浏览器数据的压缩格式(gzip) |
Content-Length | 这个头告诉浏览器回送数据的长度 |
Content-Language | 这个头告诉浏览器数据的语言类型 |
Content-Type | 告诉浏览器回送数据的类型 |
Set-Cookie | 通过该响应头在客户端保存cookie |
Refresh | 服务器通过这个头告诉浏览器,多长时间定时刷新 |
Content-Disposition | 控制浏览器以下载方式打开回送的数据 |
Transfer-Encoding | 服务器通过这个头告诉浏览器,数据是以块方式回送的 |
Expires | 控制浏览器缓存数据的时间(-1或0,代表控制浏览器不要缓存) |
Cache-Control | no-cache |
Pragma | no-cache |
【最后三个头一起用,就可以控制所有的浏览器不要缓存数据】
【为什么有三个响应头都是控制浏览器的缓存时间呢,因为不同的浏览器能够识别的响应头不同】
下图是请求百度之后的响应报文:
可以看到,百度服务器还返回了许多非通用的响应头。
4.会话跟踪
1.什么是会话?
- 客户端打开与服务器的连接发出请求到服务器响应客户端请求的全过程称之为会话。
- 会话可以简单理解为:用户开一个浏览器访问某个网站,点击多个超链接,访问服务器多个web资源,然后关闭浏览器,整个过程称之为一个会话.
- 比如打电话,我打通对方电话,只要电话不挂,这次会话就没有结束。
2.什么是会话跟踪?为什么需要会话跟踪?
会话跟踪指的是对同一个用户对服务器的连续的请求和接受响应的监视。浏览器与服务器之间的通信是通过HTTP协议进行通信的,而HTTP协议是”无状态”的协议,它不能保存客户的信息,即一次响应完成之后连接就断开了,下一次的请求需要重新连接,这样就需要判断是否是同一个用户,所以才有会话跟踪技术来实现这种要求。
通常使用的会话跟踪技术是cookie和session,关于两者的细节以及区别,在有关Servlet技术的博文中有过详细说明,可以参考:
1.【Servlet——Cookie】
2.【Servlet——Session(1)之基础知识】
3.【Servlet——Session(2)之简单应用】
4.【Servlet——Session(3)之实现原理的深入讨论】
5.【Servlet——Cookie与Session的对比】