HTTP 协议定义了浏览器(即万维网客户进程)怎样向万维网服务器请求万维网文档,以及服务器怎样把文档传送给浏览器。,它是万维网上能够可靠地交换文件(包括文本、声音、图像等各种多媒体文件)的重要基础。
大致工作流程如下图所示:
HTTP 的报文结构
HTTP 有两类报文:
- 请求报文一-从客户向服务器发送请求报文
- 响应报文一-从服务器到客户的回答
由于HTTP 是面向文本的(text-oriented),因此在报文中的每一个字段都是一些ASCII 码串,因而各个字段的长度都是不确定的。
HTTP 请求报文和响应报文都是由三个部分组成。可以看出,这两种报文格式的区别就是开始行不同。
- 开始行
用于区分是请求报文还是响应报文。在请求报文中的开始行叫做请求行(Request-Line),而在响应报文中的开始行叫做状态行(Status-Line)。在开始行的三个字段之间都以空格分隔开,最后的“CR”、“LF”表示回车和换行。 - 首部行
用来说明浏览器、服务器或报文主体的一些信息。首部可以有好几行,但也可以不使用。在每一个首部行中都有首部宇段名和它的值,每一行在结束的地方都要有“回车”和“换行”。整个首部行结束时,还有一空行将首部行和后面的实体主体分开。 - 实体主体(entity body)
在请求报文中一般都不用这个字段,而在响应报文中也可能没有这个字段。
请求报文
请求报文的第一行“请求行”只有三个内容,即方法,请求资源的URL ,以及HTTP
的版本。“方法”就是对所请求的对象进行的操作,这些方法实际上也就是一些命令,如下图所示:
下面是一个请求报文的例子:
响应报文
响应报文的第一行就是状态行,状态行包括三项内容,即HTTP 的版本,状态码,以及解释状态码的简单短语。
状态码(Status-Code)都是三位数字的,分为5 大类共33 种。例如:
- 1xx 表示通知信息的,如请求收到了或正在进行处理。
- 2xx 表示成功,如接受或知道了。
- 3xx 表示重定向,如要完成请求还必须采取进一步的行动。
- 4xx 表示客户的差错,如请求中有错误的语法或不能完成。
- 5xx 表示服务器的差错,如服务器失效无法完成请求。
常见的状态码如下:
200 OK
请求已成功,请求所希望的响应头或数据体将随此响应返回。202 Accepted
服务器已接受请求,但尚未处理。正如它可能被拒绝一样,最终该请求可能会也可能不会被执行。在异步操作的场合下,没有比发送这个状态码更方便的做法了。 返回202状态码的响应的目的是允许服务器接受其他过程的请求(例如某个每天只执行一次的基于批处理的操作),而不必让客户端一直保持与服务器的连接直到批处理操作全部完成。在接受请求处理并返回202状态码的响应应当在返回的实体中包含一些指示处理当前状态的信息,以及指向处理状态监视器或状态预测的指针,以便用户能够估计操作是否已经完成。206 Partial Content
服务器已经成功处理了部分 GET 请求。类似于 FlashGet 或者迅雷这类的 HTTP 下载工具都是使用此类响应实现断点续传或者将一个大文档分解为多个下载段同时下载。该请求必须包含 Range 头信息来指示客户端希望得到的内容范围,并且可能包含 If-Range 来作为请求条件。响应必须包含如下的头部域:Content-Range 用以指示本次响应中返回的内容的范围;如果是 Content-Type 为multipart/byteranges 的多段下载,则每一multipart 段中都应包含 Content-Range 域用以指示本段的内容范围。304 Not Modified
未修改。所请求的资源未修改,服务器返回此状态码时,不会返回任何资源。客户端通常会缓存访问过的资源,通过提供一个头信息指出客户端希望只返回在指定日期之后修改的资源305 Use Proxy
使用代理。所请求的资源必须通过代理访问400 Bad Request
语义有误,当前请求无法被服务器理解。除非进行修改,否则客户端不应该重复提交这个请求。请求参数有误。404 Not Found
请求失败,请求所希望得到的资源未被在服务器上发现。没有信息能够告诉用户这个状况到底是暂时的还是永久的。假如服务器知道情况的话,应当使用410状态码来告知旧资源因为某些内部的配置机制问题,已经永久的不可用,而且没有任何可以跳转的地址。404这个状态码被广泛应用于当服务器不想揭示到底为何请求被拒绝或者没有其他适合的响应可用的情况下。500 Internal Server Error
服务器内部错误,无法完成请求502 Bad Gateway
充当网关或代理的服务器,从远端服务器接收到了一个无效的请求504 Gateway Time-out
充当网关或代理的服务器,未及时从远端服务器获取请求
HTTP会话跟踪
HTTP 协议是无状态的(stateless)。也就是说,同一个客户第二次访问同一个服务器上的页面时,服务器的响应与第一次被访问时的相同(假定现在服务器还没有把该页面更新),因为服务器并不记得曾经访问过的这个客户,也不记得为该客户曾经服务过多少次。
HTTP的无状态特性简化了服务器的设计,使服务器更容易支持大量并发的HTTP 请求,但却无法对用户进行识别。
为了对不同用户行为进行识别,HTTP提出了Cookie机制和Session机制。详见HTTP的Cookie机制和Session机制。
HTTP常见问题
1 简述从浏览器输入地址到浏览器显示页面的过程
加入要访问的URL是http://www.tsinghua.edu.cn/chn/yxsz/index.html
- 浏览器分析链接指向页面的URL 。
- 浏览器向DNS 请求解析www.tsinghua.edu.cn 的IP 地址。
- 域名系统DNS 解析出清华大学服务器的IP 地址为166.111.4.100 。
- 浏览器与服务器建立TCP连接(在服务器端IP 地址是166.111.4.100,端口是80)
- 浏览器发出取文件命令: GET /chn/yxsz/index.html。
- 服务器www.tsinghua.edu.cn 给出响应,把文件index.html发送给浏览器。
- 释放TCP连接。
- 浏览器显示“清华大学院系设置”文件index.html中的所有文本。
2 HTTP/1.0 和 HTTP/1.1的区别
长链接
HTTP/1.0规定浏览器与服务器只保持短暂的连接,浏览器的每次请求都需要与服务器建立一个TCP连接,服务器完成请求处理后立即断开TCP连接,服务器不跟踪每个客户也不记录过去的请求。
HTTP 1.1支持长连接(PersistentConnection)和请求的流水线(Pipelining)处理,在一个TCP连接上可以传送多个HTTP请求和响应,减少了建立和关闭连接的消耗和延迟。Connection请求头的值为Keep-Alive时,客户端通知服务器返回本次请求结果后保持连接;Connection请求头的值为close时,客户端通知服务器返回本次请求结果后关闭连接。
Host头域
在HTTP/1.0中认为每台服务器都绑定一个唯一的IP地址,因此,请求消息中的URL并没有传递主机名(hostname)。但随着虚拟主机技术的发展,在一台物理服务器上可以存在多个虚拟主机(Multi-homed Web Servers),并且它们共享一个IP地址。 HTTP/1.1的请求消息和响应消息都应支持Host头域,且请求消息中如果没有Host头域会报告一个错误(400 Bad Request)。此外,服务器应该接受以绝对路径标记的资源请求。
带宽优化
情况一:HTTP/1.0中,存在一些浪费带宽的现象,例如客户端只是需要某个对象的一部分,而服务器却将整个对象送过来了。例如,客户端只需要显示一个文档的部分内容,又比如下载大文件时需要支持断点续传功能,而不是在发生断连后不得不重新下载完整的包。
HTTP/1.1中在请求消息中引入了range头域,它允许只请求资源的某个部分。在响应消息中Content-Range头域声明了返回的这部分对象的偏移值和长度。如果服务器相应地返回了对象所请求范围的内容,则响应码为206(Partial Content),它可以防止Cache将响应误以为是完整的一个对象。
情况二:请求消息中如果包含比较大的实体内容,但不确定服务器是否能够接收该请求(如是否有权限),此时若贸然发出带实体的请求,如果被拒绝也会浪费带宽。
HTTP/1.1加入了一个新的状态码100(Continue)。客户端事先发送一个只带头域的请求,如果服务器因为权限拒绝了请求,就回送响应码401(Unauthorized);如果服务器接收此请求就回送响应码100,客户端就可以继续发送带实体的完整请求了。注意,HTTP/1.0的客户端不支持100响应码。
消息传递
HTTP消息中可以包含任意长度的实体,通常它们使用Content-Length来给出消息结束标志。但是,对于很多动态产生的响应,只能通过缓冲完整的消息来判断消息的大小,但这样做会加大延迟。如果不使用长连接,还可以通过连接关闭的信号来判定一个消息的结束。
HTTP/1.1中引入了Chunked transfer-coding来解决上面这个问题,发送方将消息分割成若干个任意大小的数据块,每个数据块在发送时都会附上块的长度,最后用一个零长度的块作为消息结束的标志。这种方法允许发送方只缓冲消息的一个片段,避免缓冲整个消息带来的过载。
3 HTTP/1.1 和 HTTP/2.0的区别
HTTP/2.0采用二进制格式而非文本格式
比起像HTTP/1.x这样的文本协议,二进制协议解析起来更高效、“线上”更紧凑,更重要的是错误更少。HTTP/2.0是完全多路复用的,而非有序并阻塞的——只需一个连3接即可实现并行
HTTP/1.x 有个问题叫线端阻塞(head-of-line blocking), 它是指一个连接(connection)一次只提交一个请求的效率比较高, 多了就会变慢。 HTTP/1.1 试过用流水线(pipelining)来解决这个问题, 但是效果并不理想(数据量较大或者速度较慢的响应, 会阻碍排在他后面的请求). 此外, 由于网络媒介(intermediary )和服务器不能很好的支持流水线, 导致部署起来困难重重。而多路传输(Multiplexing)能很好的解决这些问题, 因为它能同时处理多个消息的请求和响应; 甚至可以在传输过程中将一个消息跟另外一个掺杂在一起。所以客户端只需要一个连接就能加载一个页面。使用报头压缩,HTTP/2.0降低了开销
假定一个页面有80个资源需要加载(这个数量对于今天的Web而言还是挺保守的), 而每一次请求都有1400字节的消息头(着同样也并不少见,因为Cookie和引用等东西的存在), 至少要7到8个来回去“在线”获得这些消息头。这还不包括响应时间——那只是从客户端那里获取到它们所花的时间而已。这全都由于TCP的慢启动机制,它会基于对已知有多少个包,来确定还要来回去获取哪些包 – 这很明显的限制了最初的几个来回可以发送的数据包的数量。相比之下,即使是头部轻微的压缩也可以是让那些请求只需一个来回就能搞定——有时候甚至一个包就可以了。这种开销是可以被节省下来的,特别是当你考虑移动客户端应用的时候,即使是良好条件下,一般也会看到几百毫秒的来回延迟。HTTP/2.0让服务器可以将响应主动“推送”到客户端缓存中
当浏览器请求一个网页时,服务器将会发回HTML,在服务器开始发送JavaScript、图片和CSS前,服务器需要等待浏览器解析HTML和发送所有内嵌资源的请求。服务器推送服务通过“推送”那些它认为客户端将会需要的内容到客户端的缓存中,以此来避免往返的延迟。