HTTP是什么?
首先,HTTP是什么?
HTTP 是一种 超文本传输协议(Hypertext Transfer Protocol)
是基于_TCP/IP_的应用层通信协议,它是客户端和服务器之间相互通信的标准。它规定了如何在互联网上请求和传输内容。
你在这里已经可以清楚的知道了,HTTP是客户端和服务器之间相互通信的标准,那什么是超文本传输协议
呢?
超文本传输协议可以进行文字分割:超文本(Hypertext)、传输(Transfer)、协议(Protocol) ,它们之间的关系如下
什么是超文本
在互联网早期的时候,我们输入的信息只能保存在本地,无法和其他电脑进行交互。我们保存的信息通常都以文本
即简单字符的形式存在,文本是一种能够被计算机解析的有意义的二进制数据包。而随着互联网的高速发展,两台电脑之间能够进行数据的传输后,人们不满足
只能在两台电脑之间传输文字,还想要传输图片、音频、视频,甚至点击文字或图片能够进行超链接
的跳转,那么文本的语义就被扩大了,这种语义扩大后的文本就被称为超文本(Hypertext)
。
什么是传输和协议
传输:
其实顾名思义,很好理解,简单来说就是两个站点,进行信息的沟通传递。
协议:
简单来说的话就是我们俗称的约定
和规范
,后续的操作都遵循这些约定和规范就行了
HTTP/1
HTTP/0.9
第一版的HTTP文档是1991年提出来的 HTTP/0.9
。这是有史以来最简单的协议;它仅有一个GET
方法。如果客户端要访问服务器上的一些网页,它会作出如下的简单请求:
GET /index.html
下面我们就来看看 HTTP/0.9
的一个完整的请求流程(可参考下图)。
- 因为 HTTP 都是基于 TCP 协议的,所以客户端先要根据 IP 地址、端口和服务器建立 TCP 连接,而建立连接的过程就是 TCP 协议
三次握手
的过程。 - 建立好连接之后,会发送一个
GET
请求行的信息,如GET /index.html用来获取 index.html。 服务器
接收请求信息之后,读取对应的 HTML 文件,并将数据以 ASCII 字符流返回给客户端
。- HTML 文档传输完成后,
断开
连接。
总的来说,当时的需求很简单,就是用来传输体积很小的 HTML 文件,所以 HTTP/0.9
的实现有以下三个特点。
- 第一个是只有一个请求行,并
没有 HTTP 请求头和请求体
,因为只需要一个请求行就可以完整表达客户端的需求了。 - 第二个是服务器也没有
返回头
信息,这是因为服务器端并不需要告诉客户端太多信息,只需要返回数据就可以了。 - 第三个是返回的文件内容是以
ASCII 字符流
来传输的,因为都是 HTML 格式的文件,所以使用 ASCII 字节码来传输是最合适的。
HTTP/1.0
万维网的高速发展带来了很多新的需求,首先在浏览器
中展示的不单是 HTML 文件了,还包括了 JavaScript、CSS、图片、音频、视频等不同类型的文件。而 HTTP/0.9
已经不能适用新兴网络的发展,所以这时就需要一个新的协议来支撑新兴网络,这就是 HTTP/1.0
诞生的原因。
那么该如何处理不同类型的文件呢?
前面说过,HTTP 是浏览器和服务器之间的通信语言,不过 HTTP/0.9
在建立好连接之后,只会发送类似GET /index.html的简单请求命令,并没有其他途径告诉服务器更多的信息,如文件编码、文件类型等。同样,服务器
是直接返回数据给浏览器的,也没有其他途径告诉浏览器更多的关于服务器返回的文件信息。
这种简单的交流型形式无疑不能满足传输多种类型文件的需求,那为了让客户端和服务器能更深入地交流,HTTP/1.0
引入了请求头
和响应头
,在 HTTP 发送请求时,会带上请求头
信息,服务器返回数据时,会先返回响应头
信息。
那 HTTP/1.0 是怎么通过请求头和响应头来支持多种不同类型的数据呢?
- 浏览器需要知道服务器返回的数据是什么类型的,然后
浏览器
才能根据不同的数据类型
做针对性的处理。 - 由于万维网所支持的应用变得越来越广,所以单个文件的数据量也变得越来越大。为了减轻传输性能,服务器会对数据进行
压缩
后再传输,所以浏览器需要知道服务器压缩的方法。 - 由于万维网是支持全球范围的,所以需要提供国际化的支持,服务器需要对不同的地区提供不同的语言版本,这就需要浏览器告诉服务器它想要什么
语言版本
的页面。 - 由于增加了各种不同类型的文件,而每种文件的
编码形式
又可能不一样,为了能够准确地读取文件,浏览器需要知道文件的编码类型。
基于以上问题,HTTP/1.0
的方案是通过请求头
和响应头
来进行协商,在发起请求时候会通过 HTTP 请求头告诉服务器它期待服务器返回什么类型的文件、采取什么形式的压缩、提供什么语言的文件以及文件的具体编码。最终发送出来的请求头内容如下:
accept: text/html// 期望服务器返回 html 类型的文件
accept-encoding: gzip, deflate, br // 期望服务器可以采用 gzip、deflate 或者 br 其中的一种压缩方式
accept-Charset: ISO-8859-1,utf-8 // 期望返回的文件编码是 UTF-8 或者 ISO-8859-1
accept-language: zh-CN,zh // 表示期望页面的优先语言是中文
其他新增特性
- 有的请求服务器可能无法处理,或者处理出错,这时候就需要告诉浏览器服务器最终处理该请求的情况,总不能让浏览器一直傻乎乎的等着吧,所以这就引入了
状态码
。状态码是通过响应行
的方式来通知浏览器的。 - 为了减轻服务器的压力,在 HTTP/1.0 中提供了
Cache
机制,用来缓存已经下载过的数据。 - 服务器需要统计客户端的基础信息,比如 Windows 和 macOS 的用户数量分别是多少,所以 HTTP/1.0 的请求头中还加入了
用户代理
的字段。
HTTP/1.1
不过随着技术的继续发展,需求也在不断迭代更新,很快 HTTP/1.0 也不能满足需求了,所以 HTTP/1.1
又在 HTTP/1.0 的基础之上做了大量的更新。
改进持久连接
HTTP/1.0
每进行一次 HTTP 通信,都需要经历建立 TCP 连接、传输 HTTP 数据和断开 TCP 连接三个阶段
在当时,由于通信的文件比较小,而且每个页面的引用也不多,所以这种传输形式没什么大问题。但是随着浏览器普及,单个页面中的图片文件越来越多,有时候一个页面可能包含了几百个外部引用的资源文件,如果在下载每个文件的时候,都需要经历建立 TCP 连接、传输数据和断开连接这样的步骤,无疑会增加大量无谓的开销。
为了解决这个问题,HTTP/1.1
中增加了持久连接的方法,它的特点是在一个 TCP 连接上可以传输多个 HTTP 请求,只要浏览器或者服务器没有明确断开连接,那么该 TCP 连接会一直保持
从上图可以看出,HTTP 的持久连接可以有效减少 TCP 建立连接和断开连接的次数,这样的好处是减少了服务器额外的负担,并提升整体 HTTP 的请求时长。
目前浏览器中对于同一个域名,默认允许同时建立 6 个 TCP 持久连接。
HTTP 管线化
持久连接虽然能减少 TCP 的建立和断开次数,但是它需要等待前面的请求返回之后,才能进行下一次请求。如果 TCP 通道中的某个请求因为某些原因没有及时返回,那么就会阻塞后面的所有请求,这就是著名的队头阻塞的问题。
HTTP/1.1
中试图通过管线化
的技术来解决队头阻塞的问题。HTTP/1.1 中的管线化是指将多个 HTTP 请求整批提交给服务器的技术,虽然可以整批发送请求,不过服务器依然需要根据请求顺序来回复浏览器的请求。
提供虚拟主机的支持
HTTP/1.1
的请求头中增加了 Host 字段,用来表示当前的域名地址,这样服务器就可以根据不同的 Host 值做不同的处理。
客户端 Cookie、安全机制
因为http是无状态的协议,引入Cookie
后,可以让浏览器与服务器之间进行一个状态跟踪,维护一种状态。
HTTP/2
虽然 HTTP/1.1 已经做了大量的优化,但是依然存在很多性能瓶颈,依然不能满足我们日益变化的新需求,所以又引出了HTTP/2
HTTP/1.1 的主要问题
HTTP/1.1 队头阻塞的问题
还记得我们刚说过的队头阻塞
问题吗?
如果 TCP 通道中的某个请求因为某些原因没有及时返回,那么就会阻塞后面的所有请求。
不仅如此,在浏览器处理生成页面的过程中,是非常希望能提前接收到数据的,这样就可以对这些数据做预处理操作,比如提前接收到了图片,那么就可以提前进行编解码操作,等到需要使用该图片的时候,就可以直接给出处理后的数据了,这样能让用户感受到整体速度的提升。
但队头阻塞
使得这些数据不能并行请求
,所以队头阻塞是很不利于浏览器优化的。
于是就引出了多路复用
HTTP/2 的多路复用
客户端在发送请求时会将每个请求的内容封装成不同的带有编号的二进制帧(Frame),然后将这些帧同时发送给服务端。服务端接收到数据之后,会将相同编号的帧合并为完整的请求信息。同样,服务端返回结果、客户端接收结果也遵循这个帧的拆分与组合的过程。
有了二进制分帧后,对于同一个域,客户端只需要与服务端建立一个连接即可完成通信需求,这种利用一个连接来发送多个请求的方式称为多路复用。每一条路都被称为一个 stream(流)
。
HTTP/2
使用了多路复用技术,可以将请求分成一帧一帧的数据去传输,这样带来了一个额外的好处
,就是当收到一个优先级高的请求时,比如接收到 JavaScript 或者 CSS 关键资源的请求,服务器可以暂停之前的请求来优先处理关键资源的请求。
2015 年正式发布的 HTTP/2 默认不再使用 ASCII 编码传输,而是改为二进制数据,来提升传输效率。
可以设置请求的优先级
我们知道浏览器中有些数据是非常重要的,但是在发送请求时,重要的请求可能会晚于那些不怎么重要的请求,如果服务器按照请求的顺序来回复数据,那么这个重要的数据就有可能推迟很久才能送达浏览器,这对于用户体验来说是非常不友好的。
为了解决这个问题,HTTP/2
提供了请求优先级,可以在发送请求时,标上该请求的优先级,这样服务器接收到请求之后,会优先处理优先级高的请求。
头部压缩
无论是 HTTP/1.1 还是 HTTP/2,它们都有请求头和响应头,这是浏览器和服务器的通信语言。 HTTP/2
对请求头和响应头进行了压缩,你可能觉得一个 HTTP 的头文件没有多大,压不压缩可能关系不大,但你这样想一下,在浏览器发送请求的时候,基本上都是发送 HTTP 请求头,很少有请求体的发送,通常情况下页面也有 100 个左右的资源,如果将这 100 个请求头的数据压缩为原来的 20%,那么传输效率肯定能得到大幅提升。
HTTP/3
出现HTTP/3的原因
HTTP/2
由于采用二进制分帧进行多路复用,通常只使用一个 TCP
连接进行传输,在丢包
或网络中断的情况下后面的所有数据都被阻塞。
TCP 上的队头阻塞
在数据传输的过程中,有一个数据因为网络故障或者其他原因而丢包
了,那么整个 TCP 的连接就会处于暂停状态,需要等待丢失的数据包被重新传输过来。你可以把 TCP 连接看成是一个按照顺序传输数据的管道,管道中的任意一个数据丢失了,那之后的数据都需要等待该数据的重新传输。
我们就把在 TCP
传输过程中,由于单个数据包的丢失而造成的阻塞称为 TCP 上的队头阻塞
。
TCP 建立连接的延时
除了 TCP 队头阻塞之外,TCP 的握手过程
也是影响传输效率的一个重要因素。
在传输数据之前,即建立连接的过程中,我们需要花掉 3~4 个 RTT。如果浏览器和服务器的物理距离较近,那么 1 个 RTT 的时间可能在 10 毫秒以内,也就是说总共要消耗掉 30~40 毫秒。这个时间也许用户还可以接受,但如果服务器相隔较远
,那么 1 个 RTT 就可能需要 100 毫秒以上了,这种情况下整个握手过程需要 300~400 毫秒,这时用户就能明显地感受到“慢”
了。
网络延迟又称为
RTT(Round Trip Time)
。我们把从浏览器发送一个数据包到服务器,再从服务器返回数据包到浏览器的整个往返时间称为 RTT。RTT 是反映网络性能的一个重要指标。
HTTP/2
的问题不能仅靠应用程序层来解决,因此协议的新迭代必须更新传输层。但是,创建新的传输层协议并非易事。传输协议需要硬件
供应商的支持,并且需要大多数网络运营商的部署才能普及。
幸运的是还有另一种选择。UDP
协议与 TCP
一样得到广泛支持,但前者足够简单,可以作为在其之上运行的自定义协议的基础。
因此,HTTP/3 选择了一个折衷的方法——UDP 协议,基于 UDP 实现了类似于 TCP 的多路数据流、传输可靠性等功能,我们把这套功能称为 QUIC 协议。
QUIC 协议
关于 HTTP/2 和 HTTP/3 协议栈的比较,你可以参考下图:
通过上图我们可以看出,HTTP/3 中的 QUIC
协议集合了以下几点功能。
- 实现了类似 TCP 的流量控制、传输可靠性的功能。虽然 UDP 不提供可靠性的传输,但 QUIC 在 UDP 的基础之上增加了一层来保证数据可靠性传输。它提供了数据包重传、拥塞控制以及其他一些 TCP 中存在的特性。
- 集成了 TLS 加密功能。目前 QUIC 使用的是 TLS1.3,相较于早期版本 TLS1.3 有更多的优点,其中最重要的一点是减少了握手所花费的 RTT 个数。
- 实现了 HTTP/2 中的多路复用功能。和 TCP 不同,QUIC 实现了在同一物理连接上可以有多个独立的逻辑数据流(如下图)。实现了数据流的单独传输,就解决了 TCP 中队头阻塞的问题。
- 实现了快速握手功能。由于 QUIC 是基于 UDP 的,所以 QUIC 可以实现使用 0-RTT 或者 1-RTT 来建立连接,这意味着 QUIC 可以用最快的速度来发送和接收数据,这样可以大大提升首次打开页面的速度。
最后
最近找到一个VUE的文档,它将VUE的各个知识点进行了总结,整理成了《Vue 开发必须知道的36个技巧》。内容比较详实,对各个知识点的讲解也十分到位。
有需要的小伙伴,可以点击下方卡片领取,无偿分享