[计算机网络]HTTP 1.0/HTTP 1.1/HTTP 2.0
HTTP/1.0
无状态
:服务器不跟踪不记录请求过的状态
无连接
:浏览器每次请求都需要建立tcp连接
HTTP/1.0规定浏览器和服务器保持短暂的连接。浏览器的每次请求都需要与服务器建立一个TCP连接,服务器处理完成后立即断开TCP连接(无连接),服务器不跟踪每个客户端也不记录过去的请求(无状态)
无状态导致的问题可以借助cookie/session机制来做身份认证和状态记录解决。
然而,无连接特性将会导致以下性能缺陷:
- 无法复用连接。每次发送请求的时候,都需要进行一次TCP连接,而
TCP的连接释放过程又是比较费事的
。这种无连接的特性会导致网络的利用率非常低。 - 队头堵塞(head of line blocking)。由于HTTP/1.0规定
下一个请求必须在前一个请求响应到达之后才能发送
。假设一个请求响应一直不到达,那么下一个请求就不发送,就到导致阻塞后面的请求。
为了解决这些问题,HTTP/1.1出现了。
HTTP/1.1
-
长连接。
HTTP/1.1增加了一个Connection字段,通过设置Keep-alive(默认已设置)可以保持连接不断开
,避免了每次客户端与服务器请求都要重复建立释放TCP连接,提高了网络的利用率。如果客户端想关闭HTTP连接,可以在请求头中携带Connection:false
来告知服务器关闭请求。 -
支持请求管道化(pipelining)。
基于HTTP/1.1的长连接,使得请求管线化成为可能。管线化使得请求能够“并行”传输。举个例子来说,假如响应的主体是一个html页面,页面中包含了很多img,这个时候keep-alive就起了很大的作用,能够进行“并行”发送多个请求。(注意这里的“并行”并不是真正意义上的并行传输,具体解释如下。)需要注意的是,服务器必须按照客户端请求的先后顺序依次回送相应的结果,以保证客户端能够区分出每次请求的响应内容。也就是说,HTTP管道化可以让我们把先进先出队列从客户端(请求队列)迁移到服务端(响应队列)。客户端同时发了两个请求分别来获取html和css,假如说服务器的css资源先准备就绪,服务器也会先发送html再发送css。换句话来说,只有等到html响应的资源完全传输完毕后,css响应的资源才能开始传输。也就是说,不允许同时存在两个并行的响应。
可见,HTTP/1.1还是无法解决队头阻塞(head of line blocking)的问题。同时“管道化”技术存在各种各样的问题,所以很多浏览器要么根本不支持它,要么就直接默认关闭,并且开启的条件很苛刻...而且实际上好像并没有什么用处。
那我们在谷歌控制台看到的并行请求又是怎么一回事呢?
虽然HTTP/1.1支持管道化,但是服务器也必须进行逐个响应的送回
,这个是很大的一个缺陷。实际上,现阶段的浏览器厂商采取了另外一种做法,它允许我们打开多个TCP的会话。也就是说,上图我们看到的并行,其实是不同的TCP连接上的HTTP请求和响应。这也就是我们所熟悉的浏览器对同域下并行加载6~8个资源的限制。而这,才是真正的并行!
此外,HTTP/1.1还加入了缓存处理,新的字段如cache-control,支持断点传输,以及增加了Host字段(使得一个服务器能够用来创建多个Web站点)。
HTTP/2.0
帧: HTTP/2 数据通信的最小单位
消息:指 HTTP/2 中逻辑上的 HTTP 消息。例如请求和响应等,消息由一个或多个帧组成。
流: 存在于连接中的一个虚拟通道。流可以承载双向消息,每个流都有一个唯一的整数ID。
消息: 与逻辑消息对应的完整的一系列数据帧。
- 二进制分帧
HTTP/2 采用二进制格式传输数据,而非 HTTP/1.x 的文本格式,二进制协议解析起来更高效。
HTTP/1 的请求和响应报文,都是由起始行
,首部
和实体正文(可选)
组成,各部分之间以文本换行符
分隔。
HTTP/2 将请求和响应数据分割为更小的帧,并且它们采用二进制编码。
- 多路复用
-
同域名下的所有通信都在单个TCP连接中完成。
单个连接
可以承载任意数量的双向数据流。同个域名只需要占用一个TCP连接,消除了因多个TCP连接而带来的延时和内存消耗。 -
数据流以消息的形式发送,而消息又由一个或多个帧组成,多个帧之间可以
乱序发送
,因为根据帧首部的流标识可以重新组装,这一特性,使性能有了很大的提升。 -
单个连接上可以并行交错地请求和响应,之间互不干扰。
-
在HTTP/2中,每个请求都可以带一个31bit的优先值,0表示最高优先级, 数值越大优先级越低。有了这个优先值,客户端和服务器就可以在处理不同的流时采取不同的策略,以最优的方式发送流、消息和帧。
可见,HTTP/2.0实现了真正的并行传输,它能够在一个TCP上进行任意数量HTTP请求。而这个强大的功能则是基于“二进制分帧”的特性。
- 服务器推送
- 服务端可以在发送页面HTML时主动推送其它资源,而不用等到浏览器解析到相应位置,发起请求再响应。例如服务端可以主动把JS和CSS文件推送给客户端,而不需要客户端解析HTML时再发送这些请求。
- 服务端可以主动推送,客户端也有权利选择是否接收。如果服务端推送的资源已经被浏览器缓存过,浏览器可以通过发送RST_STREAM帧来拒收。主动推送也遵守同源策略,服务器不会随便推送第三方资源给客户端。
- 头部压缩
- 在HTTP/1.x中,头部元数据都是以纯文本的形式发送的,通常会给每个请求增加500~800字节的负荷。
比如说cookie,默认情况下,浏览器会在每次请求的时候,把cookie附在header上面发送给服务器。(由于cookie比较大且每次都重复发送,一般不存储信息,只是用来做状态记录和身份认证) - HTTP/2.0使用encoder来减少需要传输的header大小,通讯双方各自cache一份header fields表,既避免了重复header的传输,又减小了需要传输的大小。高效的压缩算法可以很大的压缩header,减少发送包的数量从而降低延迟。
头部压缩的原理简介
Static Table
静态表(rfc7541#section-2.3.1),包含61个预定义Header key-value,传输的时候使用对应的索引Index替换。静态表内容具体的定义可以参考这里 rfc7541#appendix-A。
+-------+-----------------------------+---------------+
| Index | Header Name | Header Value |
+-------+-----------------------------+---------------+
| 1 | :authority | |
| 2 | :method | GET |
| 3 | :method | POST |
| 4 | :path | / |
| 5 | :path | /index.html |
| 6 | :scheme | http |
| 7 | :scheme | https |
| 8 | :status | 200 |
| 9 | :status | 204 |
| 10 | :status | 206 |
| 11 | :status | 304 |
| 12 | :status | 400 |
| 13 | :status | 404 |
| 14 | :status | 500 |
| 15 | accept-charset | |
...太多了,省略掉了
| 58 | user-agent | |
| 59 | vary | |
| 60 | via | |
| 61 | www-authenticate | |
+-------+-----------------------------+---------------+
实际传输的时候,是怎么对应的呢?举几个简单的例子:
:method GET = 2 = 00000010
:method POST = 3 = 00000011
:path / = 4 = 00000100
:path /index.html = 5 = 00000101
:scheme https = 7 = 00000111
这些很好理解,那么如果是下面这几个呢?
:authority www.laoqingcai-已注销.com
:path /api/user
:token xxxxxx
这时候仅仅使用静态表是无法压缩了,轮到Dynamic Table动态表登场了。
Dynamic Table
动态表(rfc7541#section-2.3.2),是一个FIFO队列,初始是空的,它有以下特点:
解压header的时候按需添加,每次添加的时候,放在队首,移除的时候,从队尾开始。
大小不是无限制的,可以通过SETTING Frame里的SETTINGS_HEADER_TABLE_SIZE设置,默认 256Byte。
HTTP/1.x keep-alive 与 HTTP/2 多路复用区别
- HTTP/1.x 是基于文本的,只能整体去传;HTTP/2 是基于二进制流的,可以分解为独立的帧,交错发送;
- HTTP/1.x keep-alive 必须
按照请求发送的顺序返回响应
;HTTP/2 多路复用不按序响应
; - HTTP/1.x keep-alive 为了解决
队头阻塞
,将同一个页面的资源分散到不同域名下,开启了多个 TCP 连接;HTTP/2同域名下所有通信都在单个连接上
完成; - HTTP/1.x keep-alive 单个 TCP 连接在同一时刻只能处理一个请求(两个请求的生命周期不能重叠);HTTP/2 单个 TCP 同一时刻可以发送多个请求和响应;