以前看到了关于HTTP/2.0的介绍。然而,我对请求和响应的多路复用感到困惑。所以我决定做一个演示或例子来更好地理解。
TCP连接复用
当我看到TCP连接复用时,我脑海中有很多问题,比如:
- 如何知道TCP连接是否被复用了?
- 如果TCP连接没有被复用,网络会有什么不同?
- 看起来HTTP 1.1也支持TCP连接复用。那么,两者有何区别?
- ....
经过搜索,我发现在Chrome开发者工具的Network面板中有一个名为Connection ID的列。例如,这是百度的网络图片:
根据这个问题 ↗的回答:
在Canary版本中的新的Connection ID Network Panel列可以帮助您判断是否复用了TCP连接,而不是进行握手和建立新连接。
结合上面的图片,我们可以说在百度的网络面板中:
- 对ss1.bdstatic.com的请求基于H2(HTTP/2.0)并且共享相同的TCP连接,因为只有一个连接ID。
- 对www.baidu.com 的请求基于HTTP/1.1,并且共享两个TCP连接,因为有两个连接ID。
看起来HTTP/1.1也支持TCP连接复用。那么,我如何证明H2的优势或者HTTP/1.1和2.0之间的连接复用有何区别呢?
HTTP/1.1 的连接复用会带来额外的延迟
我从网络记录中选择了两个请求,并在控制台中执行了类似的代码。HTTP/1.1的请求代码如下:
Array(13)
.fill()
.forEach(() => {
fetch('https://www.baidu.com/favicon.ico', {
credentials: 'omit',
referrer: 'https://www.baidu.com/',
referrerPolicy: 'unsafe-url',
body: null,
method: 'GET',
mode: 'cors'
})
})
而HTTP/2.0的请求代码如下:
Array(13)
.fill()
.forEach(() => {
fetch(
'https://ss3.baidu.com/6ONWsjip0QIZ8tyhnq/ps_default.gif?_t=1556369856347',
{
credentials: 'omit',
referrer: 'https://www.baidu.com/',
referrerPolicy: 'unsafe-url',
body: null,
method: 'GET',
mode: 'cors'
}
)
})
以下是结果:
HTTP1.1
HTTP2
仔细观察这些图片,我们可以发现:
- 在HTTP/1.1连接中,Chrome会为每个主机打开最多6个TCP连接,并且会复用这些连接。而在HTTP/2.0连接中,Chrome只会为每个主机打开一个TCP连接。
- 此外,在HTTP/1.1连接中,当请求使用相同的TCP连接时,Chrome会逐个发送请求。正如developers.google.com ↗所说:
在HTTP 1.0/1.1连接中,Chrome对每个主机强制使用最多六个TCP连接。如果您同时请求了十二个项目,前六个将开始,后半部分将被排队。一旦完成了前半部分中的一个请求,队列中的第一个项目将开始其请求过程。
这会在发送更多请求时带来更多的延迟。
- 而在HTTP/2.0连接上,Chrome会同时将所有请求发送到同一源,在发送更多请求时,没有额外延迟。
HTTP/1.1 连接复用的时间较短
在HTTP/1.1连接上,默认情况下Chrome会复用TCP连接,并且您可以在响应头中找到
Connection: keep-alive
但是根据MDN文档 ↗的说明:
这个连接不会一直保持打开:空闲连接会在一段时间后关闭(服务器可以使用Keep-Alive头部字段来指定连接的最小保持时间)。
而对于HTTP/2.0,根据developers.google.com ↗
所有的HTTP/2.0连接都是持久的,每个源(origin)只需要使用一个连接,这带来了许多性能上的优势。