HTTP/0.9 是于1991 年提出,主要用来在网络之间传递 HTML 超文本的内容,所以被称为超文本传输协议.
整个流程:
服务端:正确建立 TCP 连接后,接收客户端请求,处理数据,返回响应信息
客户端:构建请求 => DNS 解析查找 IP => 建立 TCP 连接 => 发起请求 => 接收响应 => 断开 TCP 连接
1994 年拨号上网出现,万维网不再局限于学术交流。随之而来的是万维网联盟 W3C 和 HTTP 工作组 HTTP-WG 的创建,致力于发展和改进 HTTP
增强内容
浏览器中展示的文件不再只是 HTML 文件类型了,还包括了 JavaScript、CSS、图片、音频、视频等不同类型的文件。
因此需要一个新的协议来支持多种类型的文件下载,这也是 HTTP/1.0 的核心诉求,而且文件格式不仅仅局限于 ASCII 编码,还有很多其他编码文件
HTTP/1.0 引入了请求头和相应头,它们都是以 Key-Value 形式保存的,在发送请求时会带上请求头信息,服务器返回数据时会先返回响应头信息。
要支持多种类型的文件,我们就需要解决以下几个问题:
基于以上问题,HTTP/1.0 的方案是通过请求头和响应头来进行协调,发起请求时会通过 HTTP 请求头告诉服务器需要什么类型的文件、采取什么形式的压缩、提供什么语言的文件以及文件的具体编码。 最终发送的请求头如下:
服务器接收到浏览器发送过来的请求头信息之后,会根据请求头的信息来准备相应数据。服务器会根据支持的压缩方法,返回匹配的响应信息。
以上就是 HTTP/1.0 支持多文件的一个基本流程
随着技术的继续发展,需求也在不断迭代更新,这就出现了 HTTP/1.1
主要变更点
HTTP/1.0 每进行一次 HTTP 通信,都会经历 建立 TCP 连接、传输 HTTP 数据和断开 TCP 连接 这三个阶段。
随着浏览器的普及,单个页面中的图片文件越来越多,有时一个页面可能包含几百个外部资源,如果每个请求都经历以上三个阶段,那会增加大量无用的开销
HTTP/1.1 中增加了持久连接的方法,在一个 TCP 连接上可以传输多个 HTTP 请求,只要浏览器或服务器没有明确断开连接,那么该 TCP 连接会一直保持。
持久连接在 HTTP/1.1 中是默认开启的,如果不需要采用持久连接,需要在 HTTP 请求头中加上 Connection: close。
目前浏览器中对于同一个域名,默认允许同时建立 6 个 TCP 持久连接。
持久连接减少了 TCP 的建立和断开次数,但是需要按顺序等待前面的请求返回之后才能进行下一次请求。 如果某个请求没有及时返回,就会阻塞后面所有请求,这就是队头阻塞问题
HTTP/1.1 试图用管线化技术来解决队头阻塞。 HTTP/1.1 中的管线化是指将多个 HTTP 请求整批提交给服务器的技术,虽然可以整批发送,但是服务器仍然需要根据请求顺序来回复浏览器的请求
同一个 IP 下可能绑定了多个虚拟主机,每个虚拟主机都有自己的域名。
HTTP/1.1 的请求头重增加了 Host 字段,用来表示当前的域名地址,服务器根据不同的 Host 值进行不同处理。
HTTP/1.0 中,需要在响应头中设置完整的数据大小,如 Content-Length: 901, 随着服务器端的发展,很多内容都不再是固定大小,很多页面都是动态生成的,因此在传输数据之前并不知道最终的数据大小,浏览器不知道何时会接收完所有的文件数据。
HTTP/1.1 通过引入 Chunk transfer 机制来解决这个问题,服务器会将数据分割成若干个数据块,每个数据块发送时会附带上上个数据块的长度,最后使用一个零长度的块作为发送数据完成的标志。
这样就提供了对动态内容的支持。
HTTP/1.1 引入了客户端 Cookie 机制和安全机制。
如果单个 TCP 的持久连接,下载 100 个资源所需要花费的时间是 100 n RTT,通过引入 CDN,就可以把整个时间缩短为 100 n RTT / (6 * CDN 个数)。
对带宽的利用率不高
TCP 的慢启动
慢启动是 TCP 减少网络拥塞的一种策略,不能改变;
同时开启了多条 TCP 连接,那么这些连接会竞争固定的贷款
多个 TCP 连接下载文件时,无法协商优先级,导致关键资源下载缓慢
HTTP/1.1 队头阻塞
当管道中当前请求没有技术之前,后续的请求只能处于阻塞状态;我们不能随意在一个管道中发送请求和接收内容。
这种等待过程中,CPU 被白白浪费了。
队头阻塞不能并行请求数据,所以很不利于浏览器优化。
特点
慢启动和 TCP 连接之间相互竞争带宽,是由于 TCP 本身的机制导致的,而队头阻塞是由于 HTTP/1.1 的机制导致的
如何解决这些问题?
1、HTTP/2 的思路就是一个域名只使用一个 TCP 长连接来传输数据,这样整个页面只会进行一次慢启动,同时也避免了多个 TCP 连接竞争带宽所带来的问题。
2、队头阻塞的问题,在 HTTP/2 中需要实现资源的并行请求,任何时候都可以将请求发送给服务器,并不需要等待其他请求地完成;服务器也可以随时返回处理好的请求资源给浏览器
多路复用机制
每个请求都有一个对应的 ID,浏览器端可以随时将请求发送给服务器。 服务器接收到这些请求后,会根据自己的喜好来决定优先处理返回哪些内容。 因为每份数据都有对应的 ID,浏览器接收到之后会筛选出相同 ID 的内容,将其拼接为完整的 HTTP 响应数据。
当收到一个优先级高的请求时,服务器可以暂停之前的请求来优先处理关键资源的请求。
以上,通过引用二进制分帧层,就实现了 HTTP 的多路复用技术
多路复用 是 HTTP/2 的最核心功能,实现了资源的并行传输。 基于二进制分帧层,HTTP/2 还有很多其他特性:
浏览器根据资源类型,在发起请求时自动向 HTTP/2 的 PRIORITY 帧中追加优先级信息,对前端开发者来说是不透明的。
一般来说,优先级:HTML > CSS > Blocking Script > Font >= Image >= Async Script
HTTP/2 还可以直接将数据提前推送到浏览器。
用户请求一个 HTML 文件时,服务器知道 HTML 页面会用到几个重要的 JS 文件和 CSS 文件,那么在接收到 HTML 请求之后,附带将要使用的 CSS 和 JS 文件一并发送给浏览器,对首次打开页面的速度起到了关键的作用。
HTTP/2 对请求头和响应头进行了压缩。
目的:在传输的过程中,简化消息内容,降低消息大小
压缩算法介绍: 通信双方各自维护一本字典,记录着某些字符对应的文本内容。
在 TCP 传输过程中,由于单个数据包的丢失而造成的阻塞称为 TCP 上的队头阻塞
HTTP/2 中,多个请求时跑在同一个 TCP 管道中的,如果其中任意一路数据出现丢包,那么就会阻塞该 TCP 连接中的所有请求。
网络延迟又称为 RTT(Round Trip Time)。 从浏览器发送一个数据包到服务器,再从服务器返回数据包到浏览器的整个往返时间称为 RTT。
HTTP/1 和 HTTP/2 都是使用 TCP 协议来传输的,如果使用 HTTPS 的话,还需要使用 TLS 协议来进行安全传输,而 TLS 也需要一个握手过程,这样就有两个握手延迟过程。
传输数据之前,需要花费 3~4 个 RTT。若是服务器相隔比较远,那么一个 RTT 可能会有 100 ms 以上,那整个握手过程就需要 300~400 ms,那么用户就能明显感觉到"慢"了
TCP 协议存在队头阻塞和建立连接延迟等缺点,却无法通过修改 TCP 协议来解决。
HTTP/2 存在一些比较严重的与 TCP 协议相关的缺陷,但由于 TCP 协议僵化,几乎不可能通过修改 TCP 协议自身来解决这些问题。
解决思路:绕过 TCP 协议,发明一个 TCP 和 UDP 之外的新的传输协议。但因为中间设备僵化,这些设备只认 TCP 和 UDP,新协议不能被很好地支持。 所以 HTTP/3 选择了一个折中协议——UDP 协议。
基于 UDP 实现了类似于 TCP 的多路数据流、传输可靠性等功能,这套功能称为 QUIC 协议。