HTTP协议是因特网的多媒体信使。HTTP可以从遍布世界的Web服务器上将这些信息快迅速,便捷,可靠地搬移到人们桌面上的Web浏览器上去。
HTTP协议主要分Web客户端和服务器。其中Web服务器是Web资源的宿主。Web资源可以包含任意媒体类型内容,HTTP协议为了标识各种媒体类型,会给通过Web传输的对象都打上MIME类型的数据标签格式。(MIME科普:最初设计MIME(Multipurpose Internet Mail Extension
,多用途因特网邮件扩展)是为了解决在不同的电子邮件系统之间搬移报文时存在的问题。HTTP随后也采用了它,用他来描述并标记多媒体内容。)
同时,每个web服务器资源都有一个名字去标识,这被称为统一资源标识符(Uniform Resource Identifier
)。URI有两种类型,一种是我们常见的统一资源定位符URL,另外一种被称为统一资源名URN。后者仍处于试验阶段,未大范围使用。
web页面可以包含多个对象,如一个页面会包括许多图片,视频,音频等内容。客户端通过向Web服务器发送请求命令来进行事务处理。服务器响应客户端请求,并传送相应数据。
请求和响应报文都有固定的规范。报文由一行一行简单字符串组成的。HTTP报文都是纯文本,而不是二进制代码,所以人们可以很方便的进行读写(但难以解析)。报文分为三部分
- 起始行 GET /index.html HTTP/1.0
- 首部字段 每个首部字段包含一个名字和一个值,为了便于解析,两者之间用冒号来分割。首部以一个空行结束。
- 主体 起始行和首部都是文本形式且都是结构化的,主体则可以包含任意的二进制数据,当然也可以包含文本。
HTTP协议的报文是通过传输控制协议(Transmission Control Protocol,TCP
)连接从一个地方搬移到另外一个地方去的。
TCP提供了
- 无差错的数据传输
- 按序传输 (数据总是会按照发送的顺序到达)
- 未分段的数据流 (可以在任意时刻以任意尺寸将数据发送出去)
在HTTP客户端向服务器发送报文之前,需要用网际协议(Internet Protocol,IP
)地址和端口号在客户端和服务器之间建立一条TCP/IP连接。首先需要将URL进行DNS解析成IP地址,再用IP地址连接Web服务器,默认端口是80。
除了客户端与服务器之外,还有许多比较重要的Web结构组件
- 代理 位于客户端和服务器之间的HTTP中间实体
- 缓存 HTTP的仓库,使常用页面的副本可以保存在离客户端更近的地方
- 网关 连接其他应用程序的特殊Web服务器
- 隧道 对HTTP通信报文进行盲转发的特殊代理
- Agent代理 发起自动HTTP请求的半智能Web客户端
URL提供了一种统一的资源命名方式,大多数URL都有同样的:”方案://服务器位置/路径”结构。
<scheme>://<user>:<password>@<host>:<port>/<path>;<params>?<query>#<frag>
几乎没有哪个URL包含了所有这些组件。
URL最重要的3个部分是方案(scheme
),主机(host
)和路径(path
)。
转义表示法包含一个百分号%,后面跟着两个表示字符ASCII码的十六进制数。
例子http://www.baidu.com/%7Ejoe
~ 126(0x7E)
HTTP报文是在HTTP应用程序之间发生的数据块。这些数据块以一些文本形式的元信息(meta-information
)开头,这些信息描述了报文的内容及含义,后面跟着可选的数据部分。这些报文在客户端,服务器和代理之间流动。
所有的报文都可以分为两类:请求报文(request message
)和响应报文(response message
)。
请求报文
<method> <request-URL> <version> <headers> <entity-body>
响应报文
<version> <status> <reason-phrase>
<headers>
<entity-body>
方法 | 描述 |
---|---|
GET | 从服务器获取一份文档 |
HEAD | 只从服务器获取文档的首部 |
POST | 向服务器发送需要处理的数据 |
PUT | 将请求的主体部分存储在服务器上 |
PUT | 对可能经过代理服务器传送到服务器上去的报文进行追踪 |
OPTIONS | 决定可以在服务器上执行哪些方法 |
DELETE | 从服务器上删除一份文档 |
并不是所有服务器都实现了上述7种方法,而且,由于HTTP设计的易于扩展,所以其他服务器可能还会实现一些自己的请求方法。
整体范围 | 已定义范围 | 分类 |
---|---|---|
100 ~ 199 | 100~101 | 信息提示 |
200~299 | 200~206 | 成功 |
300~399 | 300~305 | 重定向 |
400~499 | 400~415 | 客户端错误 |
500~599 | 500~505 | 服务器错误 |
当前的HTTP版本只为每类状态定义了几个代码,随着协议的发展,HTTP规范中会正式的定义更多的状态码,如果收到了不认识的状态码,可能是有人将其作为当前协议的扩展定义的。可以根据其所处范围,将它作为那个类别中一个普通的成员来处理。
首部分类:
- 通用首部 既可以出现在请求报文中又可以出现在响应报文中
- 请求首部 提供更多有关请求的信息
- 响应首部 提供更多有关响应的信息
- 实体首部 描述主体的长度和内容,或者资源自身
- 扩展首部 规范中没有定义的新首部
HTTP报文的第三部分是可选的实体主体部分。实体的主体是HTTP报文的负荷,就是HTTP要传输的内容。
世界上几乎所有的HTTP通信都是由TCP/IP承载的,TCP/IP是全球计算机及网络设备都在使用的一种常用的分组交换网络分层协议集。客户端应用程序可以打开一条TCP/IP连接,连接到可能运行在世界任何地方的服务器应用程序。
https://github.com:80/WilsonLiu95
1. 浏览器利用解析出主机名 github.com
2. 浏览器查询这个主机名的IP地址 192.30.252.122
3. 浏览器获得端口号 80
4. 浏览器发起到192.30.252.122
端口80的连接
5. 浏览器向服务器发送一条HTTP GET报文
6. 浏览器从服务器读取HTTP响应报文
7. 浏览器关闭TCP连接
与建立TCP连接,以及传输请求和响应报文的时间相比,事务处理时间可能是很短的。除非客户端或服务器超载,或正在处理复杂的动态资源,否则HTTP时延就是由TCP网络时延构成的。
HTTP事务时延的有以下几种主要原因
1. 客户端首先需要根据URI确定Web服务器的IP地址和端口号。其中IP地址需要通过DNS解析URL中的主机名获得,这可能花费数十秒的时间。
2. 客户端向服务器发送TCP连接请求,即著名的”三次握手”。这个值通常最多只有一两秒钟,但如果有数百个HTTP事务的话,这个值就会快速叠加上去。
3. 因特网传输报文,以及服务器处理请求报文都需要花费时间。
4. web服务器回送HTTP响应也需要时间。
这些TCP网络时延取决于硬件速度,网络和服务器的负载,请求和响应报文的尺寸,以及客户端和服务器之间的距离。TCP协议的技术复杂性也会对时延产生巨大的影响。
一下是其余一些会对HTTP产生影响,最常见的相关时延
1. TCP连接建立握手
2. TCP慢启动拥塞控制
3. 数据聚焦的Nagle算法
4. 用于捎带确认的TCP延迟确认算法
5. TIME_WAIT时延和端口耗尽
TCP连接握手需要经过一下几个步骤
1. 酷虎的向服务器发送一个小的TCP分组(通常是40-60字节)。这个分组中设置了一个特殊的SYN标记,说明这是一个连接请求。
2. 如果服务器接收了连接,就会对一些连接参数进行计算,并向客户端回送一个TCP分组,这个分组中的SYN和ACK标记都被置位了,说明连接请求已经被接收了。
3. 最后,客户端向服务器回送一条确认信息,通知它连接已成功建立。现代的TCP栈都允许客户端在这个确认分组中发送数据。
如果连接只用来传送少量的数据,这些交换过程就会严重降低HTTP的性能。小的HTTP事务可能会在TCP建立上花费50%或者更多的时间。
每个TCP段都有一个序列号和数据完整性校验和。每个段的接收者收到完好的段时,都会向发送者回送小的确认分组。如果发送者没有在指定的窗口时间内收到确认信息,发送者就认为分为已被破坏或损毁,并重发数据。
为了增加确认报文找到同向传输数据分组的可能性,很多TCP栈都实现了一种”延迟确认”算法。延迟确认算法会在一个特定的窗口时间(通常是100~200毫秒)内将输出确认存放在缓冲区中,以寻找能够捎带它的输出数据分组。如果在那个时间段内没有输出数据分组,就讲确认信息放在单独的分组中传送。
通常,延迟确认算法会引入相当大的时延,所以可以调整或者禁止延迟确认算法。
TCP数据传输的性能还取决于TCP连接的使用期(age
)。TCP连接会随着时间进行自我“调谐”,起初会限制连接的最大速度,如果数据成功传输,会随着时间的推移提高传输的速度。这种调谐被称为TCP慢启动(slow start
),用于防止因特网的突然过载和拥塞。
Nagle算法鼓励发送全尺寸(LAN上最大尺寸的分组大约是1500字节,在因特网上是几百字节)的段。只有当所有其他的分组都被确认之后,Nagle才允许发送非全尺寸的分组,如果其他分仍然在传输过程中,就将那部分数据缓存起来。只有当挂起分组被确认,或者缓存中积累了足够发送一个全尺寸分组的数据时,才会将缓存的数据发送出去。
Nagle算法会引发几种HTTP性能问题。首先小的HTTP报文无法填满一个分组,可能会因为等待那些永远不会到来的额外数据而产生时延。其次,Nagle算法与延时确认之间的交互存在问题——Nagle会阻止数据的发送,直到有确认分组抵达为止,但确认分组自身会被延迟确认算法延迟100-200毫秒。
因此,HTTP应用程序常常会在自己的栈中设置参数TCP_NODELAY,禁用Nagle算法,提高性能。
当某个TCP端点关闭TCP连接时,会在内存中维护一个小的控制块,用来记录最近所关闭连接的IP地址和端口号。这类信息会维持一小段时间,以确保在这段时间内不会创建于相同地址和端口号的新连接。
客户端每次连接到服务器上去时,都会获得一个新的端口号,以实现连接的唯一性。但由于可用的源端口数量有限,因此会出现端口耗尽的情况。就会无法建立新的连接。
解决办法:增加客户端负载生成机器的数量,或者确保客户端和服务器在循环使用几个虚拟的IP地址以增加更多的连接组合。
HTTP允许在客户端和最终的源端服务器之间存在一串HTTP中间实体(代理,高速缓存等)。可以从客户端开始,逐跳地将HTTP报文经过这些中间设备,转发到源端服务器上去(或者进行反向传输)。
在某些情况下,两个相邻的HTTP应用程序会为它们共享的连接应用一组选项。HTTP的Connection首部字段中有一个由逗号分隔的连接标签列表,这些标签为此连接指定了一些不会传播到其他连接中去的选项。
Connection首部可以承载3种不同类型的标签
- HTTP首部字段名,列出了只与此连接有关的首部
- 任意标签值,用于描述此连接的非标准选项
- 值close,说明操作完成之后需关闭这条持久连接
如果支队连接进行简单的管理,TCP的性能时延可能会叠加起来。串行加载的另外一个缺点是,有些浏览器在对象加载完毕之前无法获知对象的尺寸,而且它们可能需要尺寸信息来决定将对象放在屏幕的什么位置上,所以在加载了足够多的对象之前,无法在屏幕上显示任何内容。
以下为4种提高HTTP连接性能的技术。
- 并行连接 通过多条TCP连接发起并发的HTTP请求
- 持久连接 重用TCP连接,以消除连接及关闭时延
- 管道化连接 通过共享的TCP连接发起并发的HTTP请求
- 复用的连接 交替传送请求和响应报文 (实验阶段)
HTTP允许客户端打开多条连接,并行地执行多个HTTP事务。
并行连接可以提高符合页面的传输速度,但并行连接也有一些缺点:
1. 每个事务都会打开/关闭一条新的连接,好耗费时间和带宽
2. 由于TCP慢启动特性的存在,每条新连接的性能会有所降低
3. 可打开的并行连接数量实际上是有限的
Web客户端经常会打开到同一个站点的连接。因此,初始化了对某服务器的HTTP请求的应用程序很可能会在不久的将来对那台服务器发起更多的请求。这种性质被称为站点局部性。
因此,HTTP/1.1允许HTTP设备在事务处理结束之后将TCP连接保持在打开状态,以便为将来的HTTP请求重用现存的连接。
在事务处理结束之后仍然保持在打开状态的TCP连接被称为持久连接。非持久连接会在每个事务结束之后关闭。持久连接会在不同事务之间保持打开状态,直到客户端或服务器决定将其关闭为止。
重用已对目标服务器打开的空闲持久连接,就可以避开缓慢的连接建立阶段。而且,已经打开的连接还可以避免慢启动的拥塞适应阶段,以便更快速地进行数据的传输。
持久连接有一些比并行连接更好的地方。持久连接降低了时延和连接建立的开销,将连接保持在已调谐状态,而且减少了打开连接的潜在数量。(持久连接有两种类型:比较老的HTTP/1.0+ “keep-alive”连接,以及现代的HTTP/1.1 “persistent”连接)
并行连接与持久连接配合使用可能是最高效的方式。
允许在持久连接上可选的使用请求管道,这是相对于keep-alive
连接的又一性能优化。
在响应到达之前,可以将多条请求放入队列。当第一条请求通过网络流向地球另一端的服务器时,第二条和第三条请求也可以开始发送了。在高时延网络条件下,这样做可以降低网络的环回时间。
本文为《http权威指南》的第一部分,由第一到四章组成,介绍了HTTP的基础构件和HTTP的核心技术。希望大家能够喜欢。