HTTP进化史

引言

应用层协议是网络面试中比较热门的考点,而HTTP协议又是应用层中比较常考的点,毕竟现在做web端开发的是比较流行的,今天我们就来聊一下现在的HTTP协议是怎样一步步过来的,我们主要分成HTTP1.1之前,HTTP1.1,HTTP2.0,HTTP3这四个部分来聊。

HTTP 1.1以前

这个版本的HTTP协议是久远一点的,它比较出名的特点是使用短连接,
浏览器的每次请求都需要与服务器建立一个TCP连接,服务器处理完成后立即断开TCP连接。
这里我们留一个问题,我们知道长连接有很多的好处,那么为什么一开始HTTP选用的是短连接呢?我们到HTTP1.1再去解答它,我们接着往后看。

大名鼎鼎的HTTP1.1

时间来到了HTTP1.1,这个版本是97年发布了,距今也过去很长时间了,不过目前广泛使用的还是它,我们来看一下它相比于以前的版本多了那些新特新。

  1. 增加了持久连接。HTTP/1.0中默认使用Connection: close。在HTTP/1.1中已经默认使用Connection: keep-alive,减少了连接建立和释放的开销;
  2. 增加了host字段。HTTP1.0认为每台服务器都绑定一个唯一的IP地址,因此,请求消息中的URL并没有传递主机名(hostname)。但随着虚拟主机技术的发展,在一台物理服务器上可以存在多个虚拟主机(Multi-homed Web Servers),并且它们共享一个IP地址。HTTP1.1的请求消息和响应消息都应支持Host头域,且请求消息中如果没有Host头域会报错(400 Bad Request)。
  3. 增加了新的状态码100(继续)。100 表示请求者应当继续提出请求。 服务器返回此代码表示已收到请求的第一部分,正在等待其余部分。在发请求体之前先用请求头试探一下服务器,看服务器要不要接收请求体,再决定要不要发请求体。
  4. 在一个TCP连接上可以传送多个HTTP请求和响应,但服务器必须按照客户端请求的先后顺序依次回送响应的结果(不允许同时存在两个并行的响应),以保证客户端能够区分出每次请求的响应内容。
  5. 新增缓存处理字段。引入了实体标签e-tags和Cache-control

我们重点来聊一下第一点和第三点。

先看第一点,顺便也解答一下上面留下的问题
HTTP1.1中使用了长连接减少了重复创建TCP连接带来的开销和延迟,那为什么在最初的版本中不使用长连接呢?
我们先看一下长连接和短连接的适用场景

长连接多用于操作频繁,点对点的通讯,而且连接数不能太多情况,。每个TCP连接都需要三步握手,这需要时间,如果每个操作都是先连接,再操作的话那么处理速度会降低很多,所以每个操作完后都不断开,次处理时直接发送数据包就OK了,不用建立TCP连接。例如:数据库的连接用长连接, 如果用短连接频繁的通信会造成socket错误,而且频繁的socket 创建也是对资源的浪费。

而像WEB网站的http服务一般都用短链接,因为长连接对于服务端来说会耗费一定的资源,而像WEB网站这么频繁的成千上万甚至上亿客户端的连接用短连接会更省一些资源,如果用长连接,而且同时有成千上万的用户,如果每个用户都占用一个连接的话,那可想而知吧。所以并发量大,但每个用户无需频繁操作情况下需用短连好。

然后我们结合一下当时的历史场景,其实当时的用户上网就是单纯的浏览一个网页,以浏览为主,当时用户其实不需要发送太多的请求,而不是像现在交互场景很多,登录上B站后需要点赞和发弹幕各种操作。所以如果当时使用长连接的话,其实是很浪费资源的行为。而现在为什么适用呢,就是因为现在的网站操作变得更加频繁了,如果给用户的每次操作都进行三次握手和四次挥手,那么用户的时延就很高了,所以换成了长连接用以改善用户的体验

说完了第一点,我们在来看一下第三点,什么叫做

在一个TCP连接上可以传送多个HTTP请求和响应,但服务器必须按照客户端请求的先后顺序依次回送响应的结果(不允许同时存在两个并行的响应),以保证客户端能够区分出每次请求的响应内容。

在以前,HTTP的请求和响应是串行进行的,也就是B端发送一个请求,等待S端返回响应后,B在发送一个请求,等待S返回响应后再发送请求。不过再HTTP1.1出现了Pipelining 技术,这个技术其实是把多个HTTP请求放到一个TCP连接中一一发送,而在发送过程中不需要等待服务器对前一个请求的响应;只不过,客户端还是要按照发送请求的顺序来接收响应。)

至于标准为什么这么设定,我们可以大概推测一个原因:由于 HTTP 1.1 是个无状态的文本协议,同时返回的内容也并不能区分对应于哪个发送的请求,所以顺序必须维持一致。

比如你向服务器发送了两个请求 GET /query?q=A 和 GET /query?q=B,服务器返回了两个结果,浏览器是没有办法根据响应结果来判断响应对应于哪一个请求的。

理想情况下这样确实可以优化HTTP的请求响应所花费的时间,不过显示很骨感

  1. 一些代理服务器不能正确的处理 HTTP Pipelining。
  2. 正确的流水线实现是复杂的。 Head-of-line Blocking
  3. 队头阻塞:在建立起一个 TCP 连接之后,假设客户端在这个连接连续向服务器发送了几个请求。

按照标准,服务器应该按照收到请求的顺序返回结果,假设服务器在处理首个请求时花费了大量时间,那么后面所有的请求都需要等着首个请求结束才能响应。

所以现代浏览器默认是不开启 HTTP Pipelining 的。

不过问题还是要解决的,这就有了我们的HTTP2.0

HTTP2.0

我们先看一下HTTP2.0相比于HTTP1.1有什么改进
(1)引入二进制分帧层。二进制分帧层是http2.0性能增强的核心。http1.x在应用层以纯文本的形式进行通信,而http2.0将所有的传输信息分割为更小的消息和帧,并对它们采用二进制格式编码。
帧:http2.0通信的最小单位。通过首部的流标识符对数据进行顺序标识;
消息:由一个或多个帧组成,指逻辑上的http消息,如请求、响应。

流:可以承载双向的消息(双向指响应和请求,如http请求是一个流,响应是一个流)。每个流有唯一的整数标识符,为了防止两端流id冲突,客户端发起的流具有奇数ID,服务端发起的流具有偶数ID;
每个数据流以消息的形式发送,而消息由一个或多个帧组成。这些帧可以乱序发送,然后根据每个帧首部的流标识符重新组装。
(2)使用了多路复用技术。所有的HTTP2.0通信都在一个TCP连接上完成,这个连接可以承载任意数量的双向数据流。每个数据流拆分成互不依赖的帧,这些帧可以乱序发送(还可以分优先级发送),最后在接收端根据每个帧首部的流标识符把他们重新组合起来。
(3)头部压缩。http1.x每次通信(请求/响应)都会携带首部信息。http2.0要求客户端和服务器端各自缓存一份首部表,因此每次通信都不需要再携带首部,新增的键值会更新到表尾;此外,http2.0使用了头部压缩技术,可以让报头更紧凑,更快速传输(与gzip压缩不同,gzip是对报文内容压缩,不是头部)。
(4)请求优先级。可以为关键请求标上请求的优先级,服务器会优先处理优先级高的请求。0表示最高优先级。
(5)服务端推送。服务端可以根据客户端的请求,提前返回多个响应,推送额外的资源给客户端。只需发送一次请求,服务端可推送多次资源。(与 Websocket 消息推送有很大的不同)

我们重点看一下(1)(2)也是HTTP2.0的所重点解决的问题。
我们说HTTP1.1卡在了请求响应的并发问题上,我们看下HTTP2.0是怎么解决的。

先来解释一下多路复用,这里要区别长连接,长连接是实际上同一时间内还是只能由一个HTTP连接使用,而多路复用指的是同一时间有多个HTTP连接使用同一个TCP连接。
假如现在两个HTTP请求GET /query?q=A 和 GET /query?q=B,在2.0的传输模型下,这两个请求会分到不同的stream绑定到streamid,在每个stream中传输自己的数据并接收响应的数据。这样就解决了HTTP1.1中的阻塞问题,此时的响应就可以并行了。

现在看来应用层的阻塞暂时解决了,不要忘了运输层的阻塞,因为HTTP使用的是TCP。

HTTP3.0

由于HTTP协议使用TCP作为运输层,自然而然避免不了tcp的队头阻塞问题,在3.0中弃用了TCP改用了由UDP改进而来的QUIC(谷歌做的)。
这样就直接解决了队头阻塞问题。
QUIC的特点

  1. 实现了类似tcp的流量控制、传输可靠性的功能; 集成了TLS加密功能
  2. 实现了http2.0中多路复用功能。不同的是QUIC实现了在同意物理连接上可以有多个独立的逻辑数据流,实现了数据流的单独传输,解决了TCP层队头阻塞的问题。
  3. 实现了快速握手功能。QUIC是基于UDP的,所以QUIC可以实现使用0-RTT或1-RTT来建立连接。RTT (Round-TripTime),也就是数据包一来一回的时间消耗。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值