浏览器原理与实践系列文章内容来自极客时间李兵老师《浏览器工作原理与实践》,主要是记录自己的学习过程,基于自己的理解对内容做的一些总结,包括《宏观视角下的浏览器》《浏览器中的JS执行机制》《V8引擎工作原理》《事件循环系统》《浏览器中的页面》《网络协议》《浏览器安全》共七篇,此为第六篇
HTTP是浏览器中最重要 且使用最多 的协议,是浏览器和服务器之间的通信语言,也是互联网的基石。而随着浏览器的发展,HTTP为了能适应新的形式也在持续进化,从http0.9到http3。
超文本传输协议HTTP/0.9
HTTP/0.9是于1991年提出的,主要用于学术交流,需求很简单------用来在网络之间传递HTML超文本的内容,所以被称为超文本传输协议。 它的实现也很简单,采用了基于请求响应的模式,从客户端发出请求,服务器返回数据。
HTTP/0.9的实现有三个特点。
- 只有一个请求行,并没有HTTP请求头和请求体,因为只需要一个请求行就可以完整表达客户端的需求了。
- 服务器没有返回头信息,这是因为服务器端并不需要告诉客户端太多信息,只需要返回数据就可以了。
- 返回的文件内容是以ASCII字符流来传输的,因为都是HTML格式的文件,所以使用ASCII字节码来传输是最合适的。
HTTP/1.0
- HTTP/1.0引入了请求头和响应头,它们都是以为Key-Value形式保存的,在HTTP发送请求时,会带上请求头信息,服务器返回数据时,会先返回响应头信息。HTTP/1.0通过请求头和响应头来和服务器进行协商,在发起请求时候会通过HTTP请求头告诉服务器它期待服务器返回什么类型的文件、采取什么形式的压缩、提供什么语言的文件以及文件的具体编码。
- HTTP/1.0引入了状态码, 有的请求服务器可能无法处理,或者处理出错,这时候就需要告诉浏览器服务器最终处理该请求的情况。状态码是通过响应行的方式来通知浏览器的。
- HTTP/1.0中提供了Cache机制,用来缓存已经下载过的数据,以减轻服务器的压力。
- HTTP/1.0的请求头中还加入了用户代理的字段,服务器需要统计客户端的基础信息,比如Windows和macOS的用户数量分别是多少。
HTTP/1.1
1. 改进持久连接: HTTP/1.1中增加了持久连接的方法,它的特点是在一个TCP连接上可以传输多个HTTP请求,只要浏览器或者服务器没有明确断开连接,那么该TCP连接会一直保持。持久连接在HTTP/1.1中是默认开启的,所以不需要专门为了持久连接去HTTP请求头设置信息,如果不想要采用持久连接,可以在HTTP请求头中加上Connection: close。目前浏览器中对于同一个域名,默认允许同时建立6个TCP持久连接。
2. 不成熟的HTTP管线化: 持久连接虽然能减少TCP的建立和断开次数,但是它需要等待前面的请求返回之后,才能进行下一次请求。如果TCP通道中的某个请求因为某些原因没有及时返回,那么就会阻塞后面的所有请求,这就是队头阻塞 问题。HTTP/1.1中试图通过管线化的技术来解决队头阻塞的问题:将多个HTTP请求整批提交给服务器的技术,虽然可以整批发送请求,不过服务器依然需要根据请求顺序来回复浏览器的请求。
3. 提供虚拟主机的支持: 在HTTP/1.0中,每个域名绑定了一个唯一的IP地址,因此一个服务器只能支持一个域名。但是随着虚拟主机技术的发展,需要实现在一台物理主机上绑定多个虚拟主机,每个虚拟主机都有自己的单独的域名,这些单独的域名都公用同一个IP地址。因此,HTTP/1.1的请求头中增加了Host字段,用来表示当前的域名地址,这样服务器就可以根据不同的Host值做不同的处理。
4. 对动态生成的内容提供了完美支持: 在设计HTTP/1.0时,需要在响应头中设置完整的数据大小,如Content-Length: 901,这样浏览器就可以根据设置的数据大小来接收数据。不过随着服务器端的技术发展,很多页面的内容都是动态生成的,因此在传输数据之前并不知道最终的数据大小,这就导致了浏览器不知道何时会接收完所有的文件数据。HTTP/1.1通过引入Chunk transfer机制来解决这个问题,服务器会将数据分割成若干个任意大小的数据块,每个数据块发送时会附上上个数据块的长度,最后使用一个零长度的块作为发送数据完成的标志。这样就提供了对动态内容的支持。
5. 客户端Cookie、安全机制: HTTP/1.1引入了客户端Cookie机制和安全机制
http1的弊端
http1的最核心的优化有三点:
- 增加了持久连接;
- 浏览器为每个域名最多同时维护6个TCP持久连接;
- 使用CDN的实现域名分片机制。
http1缺点 -- 对带宽的利用率却并不理想,有三个原因:
- TCP的慢启动: 一旦一个TCP连接建立之后,就进入了发送数据状态,刚开始TCP协议会采用一个非常慢的速度去发送数据,然后慢慢加快发送数据的速度,直到发送数据的速度达到一个理想状态,这个过程称为慢启动。把每个TCP发送数据的过程看成是一辆车的启动过程,当刚进入公路时,会有从0到一个稳定速度的提速过程,TCP的慢启动就类似于该过程。慢启动是TCP为了减少网络拥塞的一种策略,是没有办法改变的。
- 同时开启了多条TCP连接,这些连接会竞争固定的带宽: 比如一个页面有200个文件,使用了3个CDN,那么加载该网页的时候就需要建立6 * 3,也就是18个TCP连接来下载资源;在下载过程中,当发现带宽不足的时候,各个TCP连接就需要动态减慢接收数据的速度。这样就会出现一个问题,因为有的TCP连接下载的是一些关键资源,如CSS文件、JavaScript文件等,而有的TCP连接下载的是图片、视频等普通的资源文件,但是多条TCP连接之间又不能协商让哪些关键资源优先下载,这样就有可能影响那些关键资源的下载速度了。
- 队头阻塞问题: 在HTTP/1.1中使用持久连接时,虽然能公用一个TCP管道,但是在一个管道中同一时刻只能处理一个请求,在当前的请求没有结束之前,其他的请求只能处于阻塞状态。这意味着不能随意在一个管道中发送请求和接收内容。
http2
http2最重要的特点为多路复用:一个域名只使用一个TCP长连接和消除队头阻塞问题。
HTTP/2如何实现多路复用:添加了一个二进制分帧层,以下为http2请求和接收过程。
- 首先,浏览器准备好请求数据,包括了请求行、请求头等信息,如果是POST方法,那么还要有请求体。
- 这些数据经过二进制分帧层处理之后,会被转换为一个个带有请求ID编号的帧,通过协议栈将这些帧发送给服务器。
- 服务器接收到所有帧之后,会将所有相同ID的帧合并为一条完整的请求信息。
- 然后服务器处理该条请求,并将处理的响应行、响应头和响应体分别发送至二进制分帧层。
- 同样,二进制分帧层会将这些响应数据转换为一个个带有请求ID编号的帧,经过协议栈发送给浏览器。
- 浏览器接收到响应帧之后,会根据ID编号将帧的数据提交给对应的请求。
HTTP/2其他特性
1. 可以设置请求的优先级: HTTP/2提供了请求优先级,可以在发送请求时,标上该请求的优先级,这样服务器接收到请求之后,会优先处理优先级高的请求。
2. 服务器推送: 当用户请求一个HTML页面之后,服务器知道该HTML页面会引用几个重要的JavaScript文件和CSS文件,那么在接收到HTML请求之后,附带将要使用的CSS文件和JavaScript文件一并发送给浏览器,这样当浏览器解析完HTML文件之后,就能直接拿到需要的CSS文件和JavaScript文件,这对首次打开页面的速度起到了至关重要的作用。
3. 头部压缩: HTTP/2对请求头和响应头进行了压缩。一个HTTP的头文件没有多大,但是浏览器发送请求的时候,基本上都是发送HTTP请求头,很少有请求体的发送,通常情况下页面也有100个左右的资源,如果将这100个请求头的数据压缩为原来的20%,那么传输效率肯定能得到大幅提升。
http3/QUIC
虽然HTTP/2解决了应用层面的队头阻塞问题,不过和HTTP/1.1一样,HTTP/2依然是基于TCP协议的,而TCP最初就是为了单连接而设计的。除了TCP队头阻塞之外,TCP的握手过程也是影响传输效率的一个重要因素。HTTP/1和HTTP/2都是使用TCP协议来传输的,而如果使用HTTPS的话,还需要使用TLS协议进行安全传输,而使用TLS也需要一个握手过程,这样就需要有两个握手延迟过程。
- 在建立TCP连接的时候,需要和服务器进行三次握手来确认连接成功,也就是说需要在消耗完1.5个RTT之后才能进行数据传输。
- 进行TLS连接,TLS有两个版本------TLS1.2和TLS1.3,每个版本建立连接所花的时间不同,大致是需要1~2个RTT
所以,在传输数据之前,就需要花掉3~4个RTT,如果距离过长,是比较耗时的。
因此,HTTP/3 选择了UDP协议,基于UDP实现了类似于 TCP的多路数据流、传输可靠性等功能,这套功能称为QUIC协议
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可以用最快的速度来发送和接收数据,这样可以大大提升首次打开页面的速度。
HTTP/3的挑战
在技术层面,HTTP/3是个近乎完美的协议。不过要将HTTP/3应用到实际环境中依然面临着诸多严峻的挑战,主要来自于以下三个方面。
第一,从目前的情况来看,服务器和浏览器端都没有对HTTP/3提供比较完整的支持。
第二,部署HTTP/3也存在着非常大的问题。因为系统内核对UDP的优化远远没有达到TCP的优化程度,这也是阻碍QUIC的一个重要原因。
第三,中间设备僵化的问题。这些设备对UDP的优化程度远远低于TCP,据统计使用QUIC协议时,大约有3%~7%的丢包率。
HTTPS
由于HTTP天生"明文"的特点,整个传输过程完全透明,任何人都能够在链路中截获、修改或者伪造请求/响应报文,数据不具有可信性。因此有了HTTPS。
通常认为,如果通信过程具备了四个特性,就可以认为是"安全"的,这四个特性是:机密性、完整性,身份认证和不可否认。
HTTPS默认端口号443,其他的什么请求-应答模式、报文结构、请求方法、URI、头字段、连接管理等等都完全沿用HTTP。它把HTTP下层的传输协议由TCP/IP换成了SSL/TLS。